You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

900 lines
32 KiB

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.bootstrapAnalyticsAsync = bootstrapAnalyticsAsync;
exports.helpGroupOrder = void 0;
exports.run = run;
exports.trackUsage = trackUsage;
function _bunyan() {
const data = _interopRequireDefault(require("@expo/bunyan"));
_bunyan = function () {
return data;
};
return data;
}
function _config() {
const data = require("@expo/config");
_config = function () {
return data;
};
return data;
}
function _boxen() {
const data = _interopRequireDefault(require("boxen"));
_boxen = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _commander() {
const data = _interopRequireWildcard(require("commander"));
_commander = function () {
return data;
};
return data;
}
function _fs() {
const data = _interopRequireDefault(require("fs"));
_fs = function () {
return data;
};
return data;
}
function _getenv() {
const data = _interopRequireDefault(require("getenv"));
_getenv = function () {
return data;
};
return data;
}
function _leven() {
const data = _interopRequireDefault(require("leven"));
_leven = function () {
return data;
};
return data;
}
function _findLastIndex() {
const data = _interopRequireDefault(require("lodash/findLastIndex"));
_findLastIndex = function () {
return data;
};
return data;
}
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
function _progress() {
const data = _interopRequireDefault(require("progress"));
_progress = function () {
return data;
};
return data;
}
function _stripAnsi() {
const data = _interopRequireDefault(require("strip-ansi"));
_stripAnsi = function () {
return data;
};
return data;
}
function _url() {
const data = _interopRequireDefault(require("url"));
_url = function () {
return data;
};
return data;
}
function _wrapAnsi() {
const data = _interopRequireDefault(require("wrap-ansi"));
_wrapAnsi = function () {
return data;
};
return data;
}
function _xdl() {
const data = require("xdl");
_xdl = function () {
return data;
};
return data;
}
function _StatusEventEmitter() {
const data = _interopRequireDefault(require("./analytics/StatusEventEmitter"));
_StatusEventEmitter = function () {
return data;
};
return data;
}
function _commands() {
const data = require("./commands");
_commands = function () {
return data;
};
return data;
}
function _accounts() {
const data = require("./commands/auth/accounts");
_accounts = function () {
return data;
};
return data;
}
function _TerminalLink() {
const data = require("./commands/utils/TerminalLink");
_TerminalLink = function () {
return data;
};
return data;
}
function _profileMethod() {
const data = require("./commands/utils/profileMethod");
_profileMethod = function () {
return data;
};
return data;
}
function _urlOpts() {
const data = _interopRequireDefault(require("./commands/utils/urlOpts"));
_urlOpts = function () {
return data;
};
return data;
}
function _log() {
const data = _interopRequireDefault(require("./log"));
_log = function () {
return data;
};
return data;
}
function _handleErrors() {
const data = require("./utils/handleErrors");
_handleErrors = function () {
return data;
};
return data;
}
function _matchFileNameOrURLFromStackTrace() {
const data = require("./utils/matchFileNameOrURLFromStackTrace");
_matchFileNameOrURLFromStackTrace = function () {
return data;
};
return data;
}
function _ora() {
const data = require("./utils/ora");
_ora = function () {
return data;
};
return data;
}
function _update() {
const data = _interopRequireDefault(require("./utils/update"));
_update = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
// We use require() to exclude package.json from TypeScript's analysis since it lives outside the
// src directory and would change the directory structure of the emitted files under the build
// directory
const packageJSON = require('../package.json');
_xdl().ApiV2.setClientName(packageJSON.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;
};
// Add support for logical command groupings
_commander().Command.prototype.helpGroup = function (name) {
if (this.commands[this.commands.length - 1]) {
this.commands[this.commands.length - 1].__helpGroup = name;
} else {
this.parent.helpGroup(name);
}
return this;
};
// A longer description that will be displayed then the command is used with --help
_commander().Command.prototype.longDescription = function (name) {
if (this.commands[this.commands.length - 1]) {
this.commands[this.commands.length - 1].__longDescription = name;
} else {
this.parent.longDescription(name);
}
return this;
};
function pad(str, width) {
// Pulled from commander for overriding
const len = Math.max(0, width - (0, _stripAnsi().default)(str).length);
return str + Array(len + 1).join(' ');
}
function humanReadableArgName(arg) {
// Pulled from commander for overriding
const nameOutput = arg.name + (arg.variadic === true ? '...' : '');
return arg.required ? `<${nameOutput}>` : `[${nameOutput}]`;
}
function breakSentence(input) {
// Break a sentence by the word after a max character count, adjusting for ansi characters
return (0, _wrapAnsi().default)(input, 72);
}
_commander().Command.prototype.prepareCommands = function () {
return this.commands.filter(function (cmd) {
// Display all commands with EXPO_DEBUG, otherwise use the noHelp option.
if (_getenv().default.boolish('EXPO_DEBUG', false)) {
return true;
}
return !['internal'].includes(cmd.__helpGroup);
}).map(function (cmd, i) {
var _cmd$__helpGroup;
const args = cmd._args.map(humanReadableArgName).join(' ');
const description = cmd._description;
// Remove alias. We still show this with --help on the command.
// const alias = cmd._alias;
// const nameWithAlias = cmd._name + (alias ? '|' + alias : '');
const nameWithAlias = cmd._name;
return [nameWithAlias + (
// Remove the redundant [options] string that's shown after every command.
// (cmd.options.length ? ' [options]' : '') +
args ? ' ' + args : ''), breakSentence(description), (_cmd$__helpGroup = cmd.__helpGroup) !== null && _cmd$__helpGroup !== void 0 ? _cmd$__helpGroup : 'misc'];
});
};
/**
* Set / get the command usage `str`.
*
* @param {String} str
* @return {String|Command}
* @api public
*/
// @ts-ignore
_commander().Command.prototype.usage = function (str) {
const args = this._args.map(function (arg) {
return humanReadableArgName(arg);
});
const commandsStr = this.commands.length ? '[command]' : '';
const argsStr = this._args.length ? args.join(' ') : '';
let usage = commandsStr + argsStr;
if (usage.length) usage += ' ';
usage += '[options]';
if (arguments.length === 0) {
return this._usage || usage;
}
this._usage = str;
return this;
};
_commander().Command.prototype.helpInformation = function () {
var _this$__longDescripti;
let desc = [];
// Use the long description if available, otherwise use the regular description.
const description = (_this$__longDescripti = this.__longDescription) !== null && _this$__longDescripti !== void 0 ? _this$__longDescripti : this._description;
if (description) {
desc = [replaceAll(breakSentence(description), '\n', pad('\n', 3)), ''];
const argsDescription = this._argsDescription;
if (argsDescription && this._args.length) {
const width = this.padWidth();
desc.push('Arguments:');
desc.push('');
this._args.forEach(({
name
}) => {
desc.push(' ' + pad(name, width) + ' ' + argsDescription[name]);
});
desc.push('');
}
}
let cmdName = this._name;
if (this._alias) {
// Here is the only place we show the command alias
cmdName = `${cmdName}|${this._alias}`;
}
// Dim the options to keep things consistent.
const usage = `${_chalk().default.bold`Usage:`} ${cmdName} ${_chalk().default.dim(this.usage())}\n`;
const commandHelp = '' + this.commandHelp();
const options = [_chalk().default.bold`Options:`, '\n' + this.optionHelp().replace(/^/gm, ' '), ''];
// return ['', usage, ...desc, ...options, commandHelp].join('\n') + '\n';
return ['', usage, ...desc, ...options, commandHelp].join(pad('\n', 3)) + '\n';
};
function replaceAll(string, search, replace) {
return string.split(search).join(replace);
}
const helpGroupOrder = ['core', 'auth', 'client', 'info', 'eject', 'publish', 'build', 'credentials', 'notifications', 'url', 'webhooks', 'upload', 'internal', 'deprecated'];
exports.helpGroupOrder = helpGroupOrder;
function sortHelpGroups(helpGroups) {
const groupOrder = [...new Set([...helpGroupOrder,
// add any others and remove duplicates
...Object.keys(helpGroups)])];
const subGroupOrder = {
core: ['init', 'start', 'start:web', 'publish', 'export']
};
const sortSubGroupWithOrder = (groupName, group) => {
const order = subGroupOrder[groupName];
if (!(order !== null && order !== void 0 && order.length)) {
return group;
}
const sortedCommands = [];
while (order.length) {
const key = order.shift();
const index = group.findIndex(item => item[0].startsWith(key));
if (index >= 0) {
const [item] = group.splice(index, 1);
sortedCommands.push(item);
}
}
return sortedCommands.concat(group);
};
// Reverse the groups
const sortedGroups = {};
while (groupOrder.length) {
const group = groupOrder.shift();
if (group in helpGroups) {
sortedGroups[group] = helpGroups[group];
}
}
return Object.keys(sortedGroups).reduce((prev, curr) => ({
...prev,
// Sort subgroups that have a defined order
[curr]: sortSubGroupWithOrder(curr, helpGroups[curr])
}), {});
}
// Extended the help renderer to add a custom format and groupings.
_commander().Command.prototype.commandHelp = function () {
if (!this.commands.length) {
return '';
}
const width = this.padWidth();
const commands = this.prepareCommands();
const helpGroups = {};
// Sort commands into helpGroups
for (const command of commands) {
const groupName = command[2];
if (!helpGroups[groupName]) {
helpGroups[groupName] = [];
}
helpGroups[groupName].push(command);
}
const sorted = sortHelpGroups(helpGroups);
// Render everything.
return ['' + _chalk().default.bold('Commands:'), '',
// Render all of the groups.
Object.values(sorted).map(group => group
// Render the command and description
.map(([cmd, description]) => {
// Dim the arguments that come after the command, this makes scanning a bit easier.
let [noArgsCmd, ...noArgsCmdArgs] = cmd.split(' ');
if (noArgsCmdArgs.length) {
noArgsCmd += ` ${_chalk().default.dim(noArgsCmdArgs.join(' '))}`;
}
// Word wrap the description.
let wrappedDescription = description;
if (description) {
// Ensure the wrapped description appears on the same padded line.
wrappedDescription = ' ' + replaceAll(description, '\n', pad('\n', width + 3));
}
const paddedName = wrappedDescription ? pad(noArgsCmd, width) : noArgsCmd;
return paddedName + wrappedDescription;
}).join('\n').replace(/^/gm, ' '))
// Double new line to add spacing between groups
.join('\n\n'), ''].join('\n');
};
_commander().default.on('--help', () => {
_log().default.log(` Run a command with --help for more info 💡`);
_log().default.log(` $ expo start --help`);
_log().default.log();
});
// 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) {
return this.action(async (...args) => {
if (!_getenv().default.boolish('EAS_BUILD', false) && !_commander().default.nonInteractive) {
try {
await (0, _profileMethod().profileMethod)(checkCliVersionAsync)();
} catch {}
}
try {
const options = args[args.length - 1];
if (options.offline) {
const {
ConnectionStatus
} = await Promise.resolve().then(() => _interopRequireWildcard(require('xdl')));
ConnectionStatus.setIsOffline(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
await Promise.all([_xdl().Analytics.flush(), _xdl().UnifiedAnalytics.flush()]);
} catch (err) {
// If the `--name` property is being used then we can be sure that the error is coming from `expo init`.
const commandName = typeof this.name === 'string' ? 'init (probably)' : this.name();
await (0, _handleErrors().handleErrorsAsync)(err, {
command: commandName
});
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, options = {}) {
this.option('--config [file]', `${_chalk().default.yellow('Deprecated:')} Use app.config.js to switch config files instead.`);
return this.asyncAction(async (projectRoot, ...args) => {
const opts = args[0];
if (!projectRoot) {
projectRoot = process.cwd();
} else {
projectRoot = _path().default.resolve(process.cwd(), projectRoot);
}
if (opts.config) {
_log().default.log(_chalk().default.yellow(`\u203A ${_chalk().default.bold('--config')} flag is deprecated. Use app.config.js instead. ${(0, _TerminalLink().learnMore)('https://expo.fyi/config-flag-migration')}`));
_log().default.newLine();
// @ts-ignore: This guards against someone passing --config without a path.
if (opts.config === true) {
_log().default.addNewLineIfNone();
_log().default.log('Please specify your custom config path:');
_log().default.log(_chalk().default.green(` expo ${this.name()} --config ${_chalk().default.cyan(`<app-config>`)}`));
_log().default.newLine();
process.exit(1);
}
const pathToConfig = _path().default.resolve(process.cwd(), opts.config);
// Warn the user when the custom config path they provided does not exist.
if (!_fs().default.existsSync(pathToConfig)) {
const relativeInput = _path().default.relative(process.cwd(), opts.config);
const formattedPath = _chalk().default.reset(pathToConfig).replace(relativeInput, _chalk().default.bold(relativeInput));
_log().default.addNewLineIfNone();
_log().default.nestedWarn(`Custom config file does not exist:\n${formattedPath}`);
_log().default.newLine();
const helpCommand = _chalk().default.green(`expo ${this.name()} --help`);
_log().default.log(`Run ${helpCommand} for more info`);
_log().default.newLine();
process.exit(1);
// throw new Error(`File at provided config path does not exist: ${pathToConfig}`);
}
(0, _config().setCustomConfigPath)(projectRoot, pathToConfig);
}
const logLines = (msg, logFn) => {
if (typeof msg === 'string') {
for (const line of msg.split('\n')) {
logFn(line);
}
} else {
logFn(msg);
}
};
const {
INTERNAL_CALLSITES_REGEX
} = await Promise.resolve().then(() => _interopRequireWildcard(require('@expo/metro-config')));
const logStackTrace = async (chunk, logFn, nestedLogFn) => {
let traceInfo;
try {
traceInfo = JSON.parse(chunk.msg);
} catch {
return logFn(chunk.msg);
}
const {
message,
stack
} = traceInfo;
_log().default.addNewLineIfNone();
logFn(_chalk().default.bold(message));
const isLibraryFrame = line => {
return line.startsWith('node_modules');
};
const stackFrames = stack.split('\n').filter(line => line);
const 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++) {
const line = stackFrames[i];
if (!line) {
continue;
}
let isCollapsed = false;
const fileNameOrUrl = (0, _matchFileNameOrURLFromStackTrace().matchFileNameOrURLFromStackTrace)(line);
if (fileNameOrUrl) {
// Use the same regex we use in Metro config to filter out traces:
isCollapsed = INTERNAL_CALLSITES_REGEX.test(fileNameOrUrl);
// Unless the user is in debug mode, skip printing the collapsed files.
if (!_log().default.isDebug && isCollapsed) {
continue;
}
}
// If a file is collapsed, print it with dim styling.
const style = isCollapsed ? _chalk().default.dim : message => message;
// Use the `at` prefix to match Node.js
nestedLogFn(style('at ' + 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, _log().default.nested);
} else {
logLines(chunk.msg, _log().default.log);
}
} 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,
onStartBuildBundle({
bundleDetails
}) {
// TODO: Unify with commands/utils/progress.ts
const platform = _xdl().PackagerLogsStream.getPlatformTagForBuildDetails(bundleDetails);
bar = new (_progress().default)(`${platform}Bundling JavaScript [:bar] :percent`, {
width: 64,
total: 100,
clear: true,
complete: '=',
incomplete: ' '
});
_log().default.setBundleProgressBar(bar);
},
onProgressBuildBundle({
progress
}) {
if (!bar || bar.complete) return;
const ticks = progress - bar.curr;
ticks > 0 && bar.tick(ticks);
},
onFinishBuildBundle({
error,
start,
end,
bundleDetails
}) {
if (bar && !bar.complete) {
bar.tick(100 - bar.curr);
}
if (bar) {
_log().default.setBundleProgressBar(null);
bar.terminate();
bar = null;
const platform = _xdl().PackagerLogsStream.getPlatformTagForBuildDetails(bundleDetails);
const totalBuildTimeMs = end.getTime() - start.getTime();
const durationSuffix = _chalk().default.gray(` ${totalBuildTimeMs}ms`);
if (error) {
_log().default.log(_chalk().default.red(`${platform}Bundling failed` + durationSuffix));
} else {
_log().default.log(_chalk().default.green(`${platform}Bundling complete` + durationSuffix));
_StatusEventEmitter().default.emit('bundleBuildFinish', {
totalBuildTimeMs
});
}
}
},
updateLogs: updater => {
const newLogChunks = updater([]);
newLogChunks.forEach(newLogChunk => {
if (newLogChunk.issueId && newLogChunk.issueCleared) {
return;
}
logWithLevel(newLogChunk);
});
}
});
// needed for validation logging to function
_xdl().ProjectUtils.attachLoggerStream(projectRoot, {
stream: {
write: chunk => {
if (chunk.tag === 'device') {
logWithLevel(chunk);
_StatusEventEmitter().default.emit('deviceLogReceive', {
deviceId: chunk.deviceId,
deviceName: chunk.deviceName
});
}
}
},
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 (options.checkConfig && (await _xdl().ProjectSettings.getCurrentStatusAsync(projectRoot)) !== 'running') {
const spinner = (0, _ora().ora)('Making sure project is set up correctly...').start();
_log().default.setSpinner(spinner);
// validate that this is a good projectDir before we try anything else
const {
Doctor
} = await Promise.resolve().then(() => _interopRequireWildcard(require('xdl')));
const status = await Doctor.validateWithoutNetworkAsync(projectRoot, {
skipSDKVersionRequirement: options.skipSDKVersionRequirement
});
if (status === 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(projectRoot, ...args);
});
};
async function bootstrapAnalyticsAsync() {
_xdl().Analytics.initializeClient('1wHTzmVgmZvNjCalKL45chlc2VN', 'https://cdp.expo.dev', packageJSON.version);
_xdl().UnifiedAnalytics.initializeClient('1wabJGd5IiuF9Q8SGlcI90v8WTs', 'https://cdp.expo.dev', packageJSON.version);
const userData = await (0, _profileMethod().profileMethod)(_xdl().UserManager.getCachedUserDataAsync, 'getCachedUserDataAsync')();
if (!(userData !== null && userData !== void 0 && userData.userId)) return;
_xdl().UnifiedAnalytics.identifyUser(userData.userId, {
userId: userData.userId,
currentConnection: userData === null || userData === void 0 ? void 0 : userData.currentConnection,
username: userData === null || userData === void 0 ? void 0 : userData.username
});
}
function trackUsage(commands = []) {
var _commands$find;
const input = process.argv[2];
const ExpoCommand = cmd => (cmd._name === input || cmd._alias === input) && input !== undefined;
const subCommand = (_commands$find = commands.find(ExpoCommand)) === null || _commands$find === void 0 ? void 0 : _commands$find._name;
if (!subCommand) return; // only track valid expo commands
_xdl().UnifiedAnalytics.logEvent('action', {
action: `expo ${subCommand}`,
source: 'expo cli',
source_version: _xdl().UnifiedAnalytics.version
});
}
async function runAsync(programName) {
try {
_registerLogs();
if (_xdl().Env.shouldEnableAnalytics()) {
await bootstrapAnalyticsAsync();
}
_xdl().UserManager.setInteractiveAuthenticationCallback(_accounts().loginOrRegisterAsync);
if (process.env.SERVER_URL) {
let serverUrl = process.env.SERVER_URL;
if (!serverUrl.startsWith('http')) {
serverUrl = `http://${serverUrl}`;
}
const parsedUrl = _url().default.parse(serverUrl);
const port = parseInt(parsedUrl.port || '', 10);
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');
}
}
// Setup our commander instance
_commander().default.name(programName);
_commander().default.version(packageJSON.version).option('--non-interactive', 'Fail, if an interactive prompt would be required to continue.');
// Load each module found in ./commands by 'registering' it with our commander instance
(0, _profileMethod().profileMethod)(_commands().registerCommands)(_commander().default);
trackUsage(_commander().default.commands); // must be after register commands
_commander().default.on('command:detach', () => {
_log().default.warn('To eject your project to ExpoKit (previously "detach"), use `expo eject`.');
process.exit(0);
});
_commander().default.on('command:diagnostics', () => {
_log().default.warn('The `expo diagnostics` command is deprecated, use `npx expo-env-info` instead.');
process.exit(0);
});
_commander().default.on('command:*', subCommand => {
let msg = `"${subCommand}" is not an expo command. See "expo --help" for the full list of commands.`;
const availableCommands = _commander().default.commands.map(cmd => cmd._name);
// finding the best match whose edit distance is less than 40% of their length.
const suggestion = availableCommands.find(commandName => (0, _leven().default)(commandName, subCommand[0]) < commandName.length * 0.4);
if (suggestion) {
msg = `"${subCommand}" is not an expo command -- did you mean ${suggestion}?\n See "expo --help" for the full list of commands.`;
}
_log().default.warn(msg);
});
if (typeof _commander().default.nonInteractive === 'undefined') {
// Commander doesn't initialize boolean args with default values.
_commander().default.nonInteractive = !process.stdin.isTTY;
}
_commander().default.parse(process.argv);
// Show help when no sub-command specified
if (_commander().default.args.length === 0) {
_commander().default.help();
}
} catch (e) {
_log().default.error(e);
throw e;
}
}
async function checkCliVersionAsync() {
// Skip checking for latest version on EAS Build
if (_getenv().default.boolish('EAS_BUILD', false)) {
return;
}
const {
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 ${packageJSON.name} available (${latest}).
You are currently using ${packageJSON.name} ${current}
Install expo-cli globally using the package manager of your choice;
for example: \`npm install -g ${packageJSON.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() {
const stream = {
level: _log().default.isDebug ? 'debug' : 'info',
stream: {
write: chunk => {
if (chunk.code) {
switch (chunk.code) {
case _xdl().LoadingEvent.START_PROGRESS_BAR:
{
const bar = new (_progress().default)(chunk.msg, {
width: 64,
total: 100,
clear: true,
complete: '=',
incomplete: ' '
});
_log().default.setBundleProgressBar(bar);
return;
}
case _xdl().LoadingEvent.TICK_PROGRESS_BAR:
{
const bar = _log().default.getProgress();
if (bar) {
bar.tick(1, chunk.msg);
}
return;
}
case _xdl().LoadingEvent.STOP_PROGRESS_BAR:
{
const bar = _log().default.getProgress();
if (bar) {
_log().default.setBundleProgressBar(null);
bar.terminate();
}
return;
}
case _xdl().LoadingEvent.START_LOADING:
(0, _ora().logNewSection)(chunk.msg || '');
return;
case _xdl().LoadingEvent.STOP_LOADING:
{
const spinner = _log().default.getSpinner();
if (spinner) {
spinner.stop();
}
return;
}
}
}
if (chunk.level === _bunyan().default.INFO) {
_log().default.log(chunk.msg);
} else if (chunk.level === _bunyan().default.WARN) {
_log().default.warn(chunk.msg);
} else if (chunk.level === _bunyan().default.DEBUG) {
_log().default.debug(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() {
const 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 => {
_log().default.error('Uncaught Error', e);
process.exit(1);
});
}
//# sourceMappingURL=exp.js.map