"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ejectAsync = ejectAsync;
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _fsExtra() {
const data = _interopRequireDefault(require("fs-extra"));
_fsExtra = function () {
return data;
};
return data;
}
function _npmPackageArg() {
const data = _interopRequireDefault(require("npm-package-arg"));
_npmPackageArg = function () {
return data;
};
return data;
}
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
function _semver() {
const data = _interopRequireDefault(require("semver"));
_semver = function () {
return data;
};
return data;
}
function _pacote() {
const data = _interopRequireDefault(require("pacote"));
_pacote = function () {
return data;
};
return data;
}
function _tempy() {
const data = _interopRequireDefault(require("tempy"));
_tempy = 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 ConfigUtils() {
const data = _interopRequireWildcard(require("@expo/config"));
ConfigUtils = function () {
return data;
};
return data;
}
function PackageManager() {
const data = _interopRequireWildcard(require("../../PackageManager"));
PackageManager = function () {
return data;
};
return data;
}
function _ProjectUtils() {
const data = require("../utils/ProjectUtils");
_ProjectUtils = function () {
return data;
};
return data;
}
function _log() {
const data = _interopRequireDefault(require("../../log"));
_log = function () {
return data;
};
return data;
}
function _prompt() {
const data = _interopRequireDefault(require("../../prompt"));
_prompt = function () {
return data;
};
return data;
}
function _accounts() {
const data = require("../../accounts");
_accounts = 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 }; }
const EXPO_APP_ENTRY = 'node_modules/expo/AppEntry.js';
async function warnIfDependenciesRequireAdditionalSetupAsync(projectRoot) {
const {
exp,
pkg: pkgJson
} = await _xdl().ProjectUtils.readConfigJsonAsync(projectRoot);
const pkgsWithExtraSetup = await _jsonFile().default.readAsync(ConfigUtils().resolveModule('expo/requiresExtraSetup.json', projectRoot, exp));
const packagesToWarn = Object.keys(pkgJson.dependencies).filter(pkgName => pkgsWithExtraSetup.hasOwnProperty(pkgName));
if (packagesToWarn.length === 0) {
return;
}
let plural = packagesToWarn.length > 1;
_log().default.nested('');
_log().default.nested(_chalk().default.yellow(`Warning: your app includes ${_chalk().default.bold(packagesToWarn.length)} package${plural ? 's' : ''} that require${plural ? '' : 's'} additional setup. See the following URL${plural ? 's' : ''} for instructions.`));
_log().default.nested(_chalk().default.yellow(`Your app may not build/run until the additional setup for ${plural ? 'these packages' : 'this package'} has been completed.`));
_log().default.nested('');
packagesToWarn.forEach(pkgName => {
_log().default.nested(_chalk().default.yellow(`- ${_chalk().default.bold(pkgName)}: ${pkgsWithExtraSetup[pkgName]}`));
});
_log().default.nested('');
}
async function ejectAsync(projectRoot, options) {
await (0, _ProjectUtils().validateGitStatusAsync)();
_log().default.nested('');
let reactNativeOptionMessage = "Bare: I'd like a bare React Native project.";
const questions = [{
type: 'list',
name: 'ejectMethod',
message: 'How would you like to eject your app?\n Read more: https://docs.expo.io/versions/latest/expokit/eject/',
default: 'bare',
choices: [{
name: reactNativeOptionMessage,
value: 'bare',
short: 'Bare'
}, {
name: "ExpoKit: I'll create or log in with an Expo account to use React Native and the Expo SDK.",
value: 'expokit',
short: 'ExpoKit'
}, {
name: "Cancel: I'll continue with my current project structure.",
value: 'cancel',
short: 'cancel'
}]
}];
const ejectMethod = options.ejectMethod || (await (0, _prompt().default)(questions, {
nonInteractiveHelp: 'Please specify eject method (bare, expokit) with the --eject-method option.'
})).ejectMethod;
if (ejectMethod === 'bare') {
await ejectToBareAsync(projectRoot, options);
_log().default.nested(_chalk().default.green('Ejected successfully!'));
_log().default.newLine();
_log().default.nested(`Before running your app on iOS, make sure you have CocoaPods installed and initialize the project:`);
_log().default.nested('');
_log().default.nested(` cd ios`);
_log().default.nested(` pod install`);
_log().default.nested('');
_log().default.nested('Then you can run the project:');
_log().default.nested('');
let packageManager = ConfigUtils().isUsingYarn(projectRoot) ? 'yarn' : 'npm';
_log().default.nested(` ${packageManager === 'npm' ? 'npm run android' : 'yarn android'}`);
_log().default.nested(` ${packageManager === 'npm' ? 'npm run ios' : 'yarn ios'}`);
await warnIfDependenciesRequireAdditionalSetupAsync(projectRoot);
} else if (ejectMethod === 'expokit') {
await (0, _accounts().loginOrRegisterIfLoggedOut)();
await _xdl().Detach.detachAsync(projectRoot, options);
(0, _log().default)(_chalk().default.green('Ejected successfully!'));
} else if (ejectMethod === 'cancel') {
// we don't want to print the survey for cancellations
(0, _log().default)('OK! If you change your mind you can run this command again.');
} else {
throw new Error(`Unrecognized eject method "${ejectMethod}". Valid options are: bare, expokit.`);
}
}
async function ejectToBareAsync(projectRoot, options) {
const useYarn = ConfigUtils().isUsingYarn(projectRoot);
const npmOrYarn = useYarn ? 'yarn' : 'npm';
const {
configPath,
configName
} = await ConfigUtils().findConfigFileAsync(projectRoot);
const {
exp,
pkg: pkgJson
} = await _xdl().ProjectUtils.readConfigJsonAsync(projectRoot);
const appJson = configName === 'app.json' ? JSON.parse((await _fsExtra().default.readFile(configPath))) : {};
/**
* Perform validations
*/
if (!exp) throw new Error(`Couldn't read ${configName}`);
if (!pkgJson) throw new Error(`Couldn't read package.json`);
if (!_xdl().Versions.gteSdkVersion(exp, '34.0.0')) {
throw new Error(`Ejecting to a bare project is only available for SDK 34 and higher`);
} // Validate that the template exists
let sdkMajorVersionNumber = _semver().default.major(exp.sdkVersion);
let templateSpec = (0, _npmPackageArg().default)(`expo-template-bare-minimum@sdk-${sdkMajorVersionNumber}`);
try {
await _pacote().default.manifest(templateSpec);
} catch (e) {
if (e.code === 'E404') {
throw new Error(`Unable to eject because an eject template for SDK ${sdkMajorVersionNumber} was not found`);
} else {
throw e;
}
}
/**
* Customize app.json
*/
let {
displayName,
name
} = await getAppNamesAsync(projectRoot);
appJson.displayName = displayName;
appJson.name = name;
if (appJson.expo.entryPoint && appJson.expo.entryPoint !== EXPO_APP_ENTRY) {
(0, _log().default)(_chalk().default.yellow(`expo.entryPoint is already configured, we recommend using "${EXPO_APP_ENTRY}`));
} else {
appJson.expo.entryPoint = EXPO_APP_ENTRY;
}
(0, _log().default)('Writing app.json...');
await _fsExtra().default.writeFile(_path().default.resolve('app.json'), JSON.stringify(appJson, null, 2));
(0, _log().default)(_chalk().default.green('Wrote to app.json, please update it manually in the future.'));
let defaultDependencies = {};
/**
* Extract the template and copy it over
*/
try {
let tempDir = _tempy().default.directory();
await _xdl().Exp.extractTemplateAppAsync(templateSpec, tempDir, appJson);
_fsExtra().default.copySync(_path().default.join(tempDir, 'ios'), _path().default.join(projectRoot, 'ios'));
_fsExtra().default.copySync(_path().default.join(tempDir, 'android'), _path().default.join(projectRoot, 'android'));
let packageJson = _fsExtra().default.readJsonSync(_path().default.join(tempDir, 'package.json'));
defaultDependencies = packageJson.dependencies;
(0, _log().default)('Successfully copied template native code.');
} catch (e) {
(0, _log().default)(_chalk().default.red(e.message));
(0, _log().default)(_chalk().default.red(`Eject failed, see above output for any issues.`));
(0, _log().default)(_chalk().default.yellow('You may want to delete the `ios` and/or `android` directories.'));
process.exit(1);
}
(0, _log().default)(`Updating your package.json...`);
if (!pkgJson.scripts) {
pkgJson.scripts = {};
}
delete pkgJson.scripts.eject;
pkgJson.scripts.start = 'react-native start';
pkgJson.scripts.ios = 'react-native run-ios';
pkgJson.scripts.android = 'react-native run-android'; // The template may have some dependencies beyond react/react-native/react-native-unimodules,
// for example RNGH and Reanimated. We should prefer the version that is already being used
// in the project for those, but swap the react/react-native/react-native-unimodules versions
// with the ones in the template.
let combinedDependencies = { ...defaultDependencies,
...pkgJson.dependencies
};
combinedDependencies['react-native'] = defaultDependencies['react-native'];
combinedDependencies['react'] = defaultDependencies['react'];
combinedDependencies['react-native-unimodules'] = defaultDependencies['react-native-unimodules'];
pkgJson.dependencies = combinedDependencies;
await _fsExtra().default.writeFile(_path().default.resolve('package.json'), JSON.stringify(pkgJson, null, 2));
(0, _log().default)(_chalk().default.green('Your package.json is up to date!'));
(0, _log().default)(`Adding entry point...`);
if (pkgJson.main !== EXPO_APP_ENTRY) {
(0, _log().default)(_chalk().default.yellow(`Removing "main": ${pkgJson.main} from package.json. We recommend using index.js instead.`));
}
delete pkgJson.main;
await _fsExtra().default.writeFile(_path().default.resolve('package.json'), JSON.stringify(pkgJson, null, 2));
const indexjs = `import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('${appJson.name}', () => App);
`;
await _fsExtra().default.writeFile(_path().default.resolve('index.js'), indexjs);
(0, _log().default)(_chalk().default.green('Added new entry points!'));
(0, _log().default)(_chalk().default.grey(`Note that using \`${npmOrYarn} start\` will now require you to run Xcode and/or Android Studio to build the native code for your project.`));
(0, _log().default)('Removing node_modules...');
await _fsExtra().default.remove('node_modules');
(0, _log().default)('Installing new packages...');
const packageManager = PackageManager().createForProject(projectRoot);
await packageManager.installAsync();
_log().default.newLine();
}
async function getAppNamesAsync(projectRoot) {
const {
configPath,
configName
} = await ConfigUtils().findConfigFileAsync(projectRoot);
const {
exp,
pkg: pkgJson
} = await ConfigUtils().readConfigJsonAsync(projectRoot);
const appJson = configName === 'app.json' ? JSON.parse((await _fsExtra().default.readFile(configPath))) : {};
let {
displayName,
name
} = appJson;
if (!displayName || !name) {
(0, _log().default)("We have a couple of questions to ask you about how you'd like to name your app:");
({
displayName,
name
} = await (0, _prompt().default)([{
name: 'displayName',
message: "What should your app appear as on a user's home screen?",
default: name || exp.name,
validate: s => {
return s.length > 0 ? true : 'App display name cannot be empty.';
}
}, {
name: 'name',
message: 'What should your Android Studio and Xcode projects be called?',
default: pkgJson.name ? stripDashes(pkgJson.name) : undefined,
validate: s => {
if (s.length === 0) {
return 'Project name cannot be empty.';
} else if (s.indexOf('-') !== -1 || s.indexOf(' ') !== -1) {
return 'Project name cannot contain hyphens or spaces.';
}
return true;
}
}], {
nonInteractiveHelp: 'Please specify "displayName" and "name" in app.json.'
}));
}
return {
displayName,
name
};
}
function stripDashes(s) {
let ret = '';
for (let c of s) {
if (c !== ' ' && c !== '-') {
ret += c;
}
}
return ret;
}
//# sourceMappingURL=../../__sourcemaps__/commands/eject/Eject.js.map