"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