// Copyright 2015-present 650 Industries. All rights reserved. 'use strict'; // Set EXPO_VIEW_DIR to universe/exponent to test locally Object.defineProperty(exports, "__esModule", { value: true }); exports.prepareDetachedBuildAsync = exports.detachAsync = undefined; let detachAsync = exports.detachAsync = (() => { var _ref = _asyncToGenerator(function* (projectRoot, options) { let user = yield (_User || _load_User()).default.ensureLoggedInAsync(); if (!user) { throw new Error('Internal error -- somehow detach is being run in offline mode.'); } let username = user.username; let { exp } = yield (_ProjectUtils || _load_ProjectUtils()).readConfigJsonAsync(projectRoot); let experienceName = `@${username}/${exp.slug}`; let experienceUrl = `exp://exp.host/${experienceName}`; // Check to make sure project isn't fully detached already let hasIosDirectory = (0, (_ExponentTools || _load_ExponentTools()).isDirectory)(_path.default.join(projectRoot, 'ios')); let hasAndroidDirectory = (0, (_ExponentTools || _load_ExponentTools()).isDirectory)(_path.default.join(projectRoot, 'android')); if (hasIosDirectory && hasAndroidDirectory) { throw new (_XDLError || _load_XDLError()).default((_ErrorCode || _load_ErrorCode()).default.DIRECTORY_ALREADY_EXISTS, 'Error detaching. `ios` and `android` directories already exist.'); } // Project was already detached on Windows or Linux if (!hasIosDirectory && hasAndroidDirectory && process.platform === 'darwin') { let response = yield yesnoAsync(`This will add an Xcode project and leave your existing Android project alone. Enter 'yes' to continue:`); if (!response) { console.log('Exiting...'); return false; } } if (hasIosDirectory && !hasAndroidDirectory) { throw new Error('`ios` directory already exists. Please remove it and try again.'); } console.log('Validating project manifest...'); const configName = yield (_ProjectUtils || _load_ProjectUtils()).configFilenameAsync(projectRoot); if (!exp.name) { throw new Error(`${configName} is missing \`name\``); } if (!exp.android || !exp.android.package) { throw new Error(`${configName} is missing android.package field. See https://docs.expo.io/versions/latest/guides/configuration.html#package`); } if (!exp.sdkVersion) { throw new Error(`${configName} is missing \`sdkVersion\``); } let majorSdkVersion = (0, (_ExponentTools || _load_ExponentTools()).parseSdkMajorVersion)(exp.sdkVersion); if (majorSdkVersion < 16) { throw new Error(`${configName} must be updated to SDK 16.0.0 or newer to be detached.`); } const versions = yield (_Versions || _load_Versions()).versionsAsync(); let sdkVersionConfig = versions.sdkVersions[exp.sdkVersion]; if (!sdkVersionConfig || !sdkVersionConfig.androidExpoViewUrl || !sdkVersionConfig.iosExpoViewUrl) { if (process.env.EXPO_VIEW_DIR) { console.warn(`Detaching is not supported for SDK ${exp.sdkVersion}; ignoring this because you provided EXPO_VIEW_DIR`); sdkVersionConfig = {}; } else { throw new Error(`Detaching is not supported for SDK version ${exp.sdkVersion}`); } } // Modify exp.json exp.isDetached = true; if (!exp.detach) { exp.detach = {}; } if (!exp.detach.scheme) { let detachedUUID = (_uuid || _load_uuid()).default.v4().replace(/-/g, ''); exp.detach.scheme = `exp${detachedUUID}`; } let expoDirectory = _path.default.join(projectRoot, '.expo-source'); (_mkdirp || _load_mkdirp()).default.sync(expoDirectory); const context = (_StandaloneContext || _load_StandaloneContext()).default.createUserContext(projectRoot, exp, experienceUrl); // iOS let isIosSupported = true; if (process.platform !== 'darwin') { if (options && options.force) { console.warn(`You are not running macOS, but have provided the --force option, so we will attempt to generate an iOS project anyway. This might fail.`); } else { console.warn(`Skipping iOS because you are not running macOS.`); isIosSupported = false; } } if (!hasIosDirectory && isIosSupported) { yield detachIOSAsync(context); exp = (_IosWorkspace || _load_IosWorkspace()).addDetachedConfigToExp(exp, context); exp.detach.iosExpoViewUrl = sdkVersionConfig.iosExpoViewUrl; } // Android if (!hasAndroidDirectory) { let androidDirectory = _path.default.join(expoDirectory, 'android'); (_rimraf || _load_rimraf()).default.sync(androidDirectory); (_mkdirp || _load_mkdirp()).default.sync(androidDirectory); if ((_Versions || _load_Versions()).gteSdkVersion(exp, '24.0.0')) { yield detachAndroidAsync(context, sdkVersionConfig.androidExpoViewUrl); } else { yield (_OldAndroidDetach || _load_OldAndroidDetach()).detachAndroidAsync(projectRoot, androidDirectory, exp.sdkVersion, experienceUrl, exp, sdkVersionConfig.androidExpoViewUrl); } exp.detach.androidExpoViewUrl = sdkVersionConfig.androidExpoViewUrl; } console.log('Writing ExpoKit configuration...'); // Update exp.json/app.json // if we're writing to app.json, we need to place the configuration under the expo key const nameToWrite = yield (_ProjectUtils || _load_ProjectUtils()).configFilenameAsync(projectRoot); if (nameToWrite === 'app.json') { exp = { expo: exp }; } yield (_fsExtra || _load_fsExtra()).default.writeFile(_path.default.join(projectRoot, nameToWrite), JSON.stringify(exp, null, 2)); console.log('Finished detaching your project! Look in the `android` and `ios` directories for the respective native projects. Follow the ExpoKit guide at https://docs.expo.io/versions/latest/guides/expokit.html to get your project running.\n'); return true; }); return function detachAsync(_x, _x2) { return _ref.apply(this, arguments); }; })(); /** * Create a detached Expo iOS app pointing at the given project. */ let detachIOSAsync = (() => { var _ref2 = _asyncToGenerator(function* (context) { yield (_IosWorkspace || _load_IosWorkspace()).createDetachedAsync(context); console.log('Configuring iOS project...'); yield (_IosNSBundle || _load_IosNSBundle()).configureAsync(context); console.log(`iOS detach is complete!`); }); return function detachIOSAsync(_x3) { return _ref2.apply(this, arguments); }; })(); let regexFileAsync = (() => { var _ref3 = _asyncToGenerator(function* (filename, regex, replace) { let file = yield (_fsExtra || _load_fsExtra()).default.readFile(filename); let fileString = file.toString(); yield (_fsExtra || _load_fsExtra()).default.writeFile(filename, fileString.replace(regex, replace)); }); return function regexFileAsync(_x4, _x5, _x6) { return _ref3.apply(this, arguments); }; })(); let detachAndroidAsync = (() => { var _ref4 = _asyncToGenerator(function* (context, expoViewUrl) { if (context.type !== 'user') { throw new Error(`detachAndroidAsync only supports user standalone contexts`); } console.log('Moving Android project files...'); let androidProjectDirectory = _path.default.join(context.data.projectPath, 'android'); let tmpExpoDirectory; if (process.env.EXPO_VIEW_DIR) { // Only for testing yield (_AndroidShellApp || _load_AndroidShellApp()).copyInitialShellAppFilesAsync(_path.default.join(process.env.EXPO_VIEW_DIR, 'android'), androidProjectDirectory, true); } else { tmpExpoDirectory = _path.default.join(context.data.projectPath, 'temp-android-directory'); (_mkdirp || _load_mkdirp()).default.sync(tmpExpoDirectory); console.log('Downloading Android code...'); yield (_Api || _load_Api()).default.downloadAsync(expoViewUrl, tmpExpoDirectory, { extract: true }); yield (_AndroidShellApp || _load_AndroidShellApp()).copyInitialShellAppFilesAsync(tmpExpoDirectory, androidProjectDirectory, true); } console.log('Updating Android app...'); yield (_AndroidShellApp || _load_AndroidShellApp()).runShellAppModificationsAsync(context, true); // Clean up console.log('Cleaning up Android...'); if (!process.env.EXPO_VIEW_DIR) { (0, (_ExponentTools || _load_ExponentTools()).rimrafDontThrow)(tmpExpoDirectory); } console.log('Android detach is complete!\n'); }); return function detachAndroidAsync(_x7, _x8) { return _ref4.apply(this, arguments); }; })(); let ensureBuildConstantsExistsIOSAsync = (() => { var _ref5 = _asyncToGenerator(function* (configFilePath) { // EXBuildConstants is included in newer ExpoKit projects. // create it if it doesn't exist. const doesBuildConstantsExist = (_fsExtra || _load_fsExtra()).default.existsSync(_path.default.join(configFilePath, 'EXBuildConstants.plist')); if (!doesBuildConstantsExist) { yield (_IosPlist || _load_IosPlist()).createBlankAsync(configFilePath, 'EXBuildConstants'); console.log('Created `EXBuildConstants.plist` because it did not exist yet'); } }); return function ensureBuildConstantsExistsIOSAsync(_x9) { return _ref5.apply(this, arguments); }; })(); let _getIosExpoKitVersionThrowErrorAsync = (() => { var _ref6 = _asyncToGenerator(function* (iosProjectDirectory) { let expoKitVersion = ''; const podfileLockPath = _path.default.join(iosProjectDirectory, 'Podfile.lock'); try { const podfileLock = yield (_fsExtra || _load_fsExtra()).default.readFile(podfileLockPath, 'utf8'); const expoKitVersionRegex = /ExpoKit\/Core\W?\(([0-9\.]+)\)/gi; let match = expoKitVersionRegex.exec(podfileLock); expoKitVersion = match[1]; } catch (e) { throw new Error(`Unable to read ExpoKit version from Podfile.lock. Make sure your project depends on ExpoKit. (${e})`); } return expoKitVersion; }); return function _getIosExpoKitVersionThrowErrorAsync(_x10) { return _ref6.apply(this, arguments); }; })(); let prepareDetachedBuildIosAsync = (() => { var _ref7 = _asyncToGenerator(function* (projectDir, args) { const { exp } = yield (_ProjectUtils || _load_ProjectUtils()).readConfigJsonAsync(projectDir); if (exp) { return prepareDetachedUserContextIosAsync(projectDir, exp, args); } else { return prepareDetachedServiceContextIosAsync(projectDir, args); } }); return function prepareDetachedBuildIosAsync(_x11, _x12) { return _ref7.apply(this, arguments); }; })(); let prepareDetachedServiceContextIosAsync = (() => { var _ref8 = _asyncToGenerator(function* (projectDir, args) { // service context // TODO: very brittle hack: the paths here are hard coded to match the single workspace // path generated inside IosShellApp. When we support more than one path, this needs to // be smarter. const workspaceSourcePath = _path.default.join(projectDir, 'default'); const buildFlags = (_StandaloneBuildFlags || _load_StandaloneBuildFlags()).default.createIos('Release', { workspaceSourcePath }); const context = (_StandaloneContext || _load_StandaloneContext()).default.createServiceContext(_path.default.join(projectDir, '..', '..'), null, null, null, buildFlags, null, null); const { iosProjectDirectory, supportingDirectory } = (_IosWorkspace || _load_IosWorkspace()).getPaths(context); const expoKitVersion = yield _getIosExpoKitVersionThrowErrorAsync(iosProjectDirectory); // use prod api keys if available const prodApiKeys = yield _readDefaultApiKeysAsync(_path.default.join(context.data.expoSourcePath, '__internal__', 'keys.json')); yield (_IosPlist || _load_IosPlist()).modifyAsync(supportingDirectory, 'EXBuildConstants', function (constantsConfig) { // verify that we are actually in a service context and not a misconfigured project const contextType = constantsConfig.STANDALONE_CONTEXT_TYPE; if (contextType !== 'service') { throw new Error('Unable to configure a project which has no app.json and also no STANDALONE_CONTEXT_TYPE.'); } constantsConfig.EXPO_RUNTIME_VERSION = expoKitVersion; if (prodApiKeys) { constantsConfig.DEFAULT_API_KEYS = prodApiKeys; } return constantsConfig; }); return; }); return function prepareDetachedServiceContextIosAsync(_x13, _x14) { return _ref8.apply(this, arguments); }; })(); let _readDefaultApiKeysAsync = (() => { var _ref9 = _asyncToGenerator(function* (jsonFilePath) { if ((_fsExtra || _load_fsExtra()).default.existsSync(jsonFilePath)) { let keys = {}; const allKeys = yield new (_jsonFile || _load_jsonFile()).default(jsonFilePath).readAsync(); const validKeys = ['AMPLITUDE_KEY', 'GOOGLE_MAPS_IOS_API_KEY']; for (const key in allKeys) { if (allKeys.hasOwnProperty(key) && validKeys.includes(key)) { keys[key] = allKeys[key]; } } return keys; } return null; }); return function _readDefaultApiKeysAsync(_x15) { return _ref9.apply(this, arguments); }; })(); let prepareDetachedUserContextIosAsync = (() => { var _ref10 = _asyncToGenerator(function* (projectDir, exp, args) { const context = (_StandaloneContext || _load_StandaloneContext()).default.createUserContext(projectDir, exp); let { iosProjectDirectory, supportingDirectory } = (_IosWorkspace || _load_IosWorkspace()).getPaths(context); console.log(`Preparing iOS build at ${iosProjectDirectory}...`); // These files cause @providesModule naming collisions // but are not available until after `pod install` has run. let podsDirectory = _path.default.join(iosProjectDirectory, 'Pods'); if (!(0, (_ExponentTools || _load_ExponentTools()).isDirectory)(podsDirectory)) { throw new Error(`Can't find directory ${podsDirectory}, make sure you've run pod install.`); } let rnPodDirectory = _path.default.join(podsDirectory, 'React'); if ((0, (_ExponentTools || _load_ExponentTools()).isDirectory)(rnPodDirectory)) { let rnFilesToDelete = yield (0, (_globPromise || _load_globPromise()).default)(rnPodDirectory + '/**/*.@(js|json)'); if (rnFilesToDelete) { for (let i = 0; i < rnFilesToDelete.length; i++) { yield (_fsExtra || _load_fsExtra()).default.unlink(rnFilesToDelete[i]); } } } // insert expo development url into iOS config if (!args.skipXcodeConfig) { // populate EXPO_RUNTIME_VERSION from ExpoKit pod version const expoKitVersion = yield _getIosExpoKitVersionThrowErrorAsync(iosProjectDirectory); // populate development url let devUrl = yield (_UrlUtils || _load_UrlUtils()).constructManifestUrlAsync(projectDir); // populate default api keys const defaultApiKeys = yield _readDefaultApiKeysAsync(_path.default.join(podsDirectory, 'ExpoKit', 'template-files', 'keys.json')); yield ensureBuildConstantsExistsIOSAsync(supportingDirectory); yield (_IosPlist || _load_IosPlist()).modifyAsync(supportingDirectory, 'EXBuildConstants', function (constantsConfig) { constantsConfig.developmentUrl = devUrl; constantsConfig.EXPO_RUNTIME_VERSION = expoKitVersion; if (defaultApiKeys) { constantsConfig.DEFAULT_API_KEYS = defaultApiKeys; } return constantsConfig; }); } }); return function prepareDetachedUserContextIosAsync(_x16, _x17, _x18) { return _ref10.apply(this, arguments); }; })(); let prepareDetachedBuildAsync = exports.prepareDetachedBuildAsync = (() => { var _ref11 = _asyncToGenerator(function* (projectDir, args) { if (args.platform === 'ios') { yield prepareDetachedBuildIosAsync(projectDir, args); } else { let { exp } = yield (_ProjectUtils || _load_ProjectUtils()).readConfigJsonAsync(projectDir); let buildConstantsFileName = (_Versions || _load_Versions()).gteSdkVersion(exp, '24.0.0') ? 'DetachBuildConstants.java' : 'ExponentBuildConstants.java'; let androidProjectDirectory = _path.default.join(projectDir, 'android'); let expoBuildConstantsMatches = yield (0, (_globPromise || _load_globPromise()).default)(androidProjectDirectory + '/**/' + buildConstantsFileName); if (expoBuildConstantsMatches && expoBuildConstantsMatches.length) { let expoBuildConstants = expoBuildConstantsMatches[0]; let devUrl = yield (_UrlUtils || _load_UrlUtils()).constructManifestUrlAsync(projectDir); yield regexFileAsync(expoBuildConstants, /DEVELOPMENT_URL \= \"[^\"]*\"\;/, `DEVELOPMENT_URL = "${devUrl}";`); } } }); return function prepareDetachedBuildAsync(_x19, _x20) { return _ref11.apply(this, arguments); }; })(); var _mkdirp; function _load_mkdirp() { return _mkdirp = _interopRequireDefault(require('mkdirp')); } var _fsExtra; function _load_fsExtra() { return _fsExtra = _interopRequireDefault(require('fs-extra')); } var _jsonFile; function _load_jsonFile() { return _jsonFile = _interopRequireDefault(require('@expo/json-file')); } var _path = _interopRequireDefault(require('path')); var _rimraf; function _load_rimraf() { return _rimraf = _interopRequireDefault(require('rimraf')); } var _globPromise; function _load_globPromise() { return _globPromise = _interopRequireDefault(require('glob-promise')); } var _uuid; function _load_uuid() { return _uuid = _interopRequireDefault(require('uuid')); } var _yesno; function _load_yesno() { return _yesno = _interopRequireDefault(require('yesno')); } var _ExponentTools; function _load_ExponentTools() { return _ExponentTools = require('./ExponentTools'); } var _IosPlist; function _load_IosPlist() { return _IosPlist = _interopRequireWildcard(require('./IosPlist')); } var _IosNSBundle; function _load_IosNSBundle() { return _IosNSBundle = _interopRequireWildcard(require('./IosNSBundle')); } var _IosWorkspace; function _load_IosWorkspace() { return _IosWorkspace = _interopRequireWildcard(require('./IosWorkspace')); } var _AndroidShellApp; function _load_AndroidShellApp() { return _AndroidShellApp = _interopRequireWildcard(require('./AndroidShellApp')); } var _OldAndroidDetach; function _load_OldAndroidDetach() { return _OldAndroidDetach = _interopRequireWildcard(require('./OldAndroidDetach')); } var _Api; function _load_Api() { return _Api = _interopRequireDefault(require('../Api')); } var _ErrorCode; function _load_ErrorCode() { return _ErrorCode = _interopRequireDefault(require('../ErrorCode')); } var _ProjectUtils; function _load_ProjectUtils() { return _ProjectUtils = _interopRequireWildcard(require('../project/ProjectUtils')); } var _User; function _load_User() { return _User = _interopRequireDefault(require('../User')); } var _XDLError; function _load_XDLError() { return _XDLError = _interopRequireDefault(require('../XDLError')); } var _StandaloneBuildFlags; function _load_StandaloneBuildFlags() { return _StandaloneBuildFlags = _interopRequireDefault(require('./StandaloneBuildFlags')); } var _StandaloneContext; function _load_StandaloneContext() { return _StandaloneContext = _interopRequireDefault(require('./StandaloneContext')); } var _UrlUtils; function _load_UrlUtils() { return _UrlUtils = _interopRequireWildcard(require('../UrlUtils')); } var _Utils; function _load_Utils() { return _Utils = _interopRequireWildcard(require('../Utils')); } var _Versions; function _load_Versions() { return _Versions = _interopRequireWildcard(require('../Versions')); } 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)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } function yesnoAsync(question) { return new Promise(resolve => { (_yesno || _load_yesno()).default.ask(question, null, ok => { resolve(ok); }); }); } //# sourceMappingURL=../__sourcemaps__/detach/Detach.js.map