1"use strict"; 2 3Object.defineProperty(exports, "__esModule", { 4 value: true 5}); 6var _exportNames = { 7 getConfig: true, 8 getPackageJson: true, 9 getConfigFilePaths: true, 10 modifyConfigAsync: true, 11 getWebOutputPath: true, 12 getNameFromConfig: true, 13 getDefaultTarget: true, 14 getProjectConfigDescription: true, 15 getProjectConfigDescriptionWithPaths: true 16}; 17exports.getConfig = getConfig; 18exports.getConfigFilePaths = getConfigFilePaths; 19exports.getDefaultTarget = getDefaultTarget; 20exports.getNameFromConfig = getNameFromConfig; 21exports.getPackageJson = getPackageJson; 22exports.getProjectConfigDescription = getProjectConfigDescription; 23exports.getProjectConfigDescriptionWithPaths = getProjectConfigDescriptionWithPaths; 24exports.getWebOutputPath = getWebOutputPath; 25exports.modifyConfigAsync = modifyConfigAsync; 26 27function _jsonFile() { 28 const data = _interopRequireDefault(require("@expo/json-file")); 29 30 _jsonFile = function () { 31 return data; 32 }; 33 34 return data; 35} 36 37function _fs() { 38 const data = _interopRequireDefault(require("fs")); 39 40 _fs = function () { 41 return data; 42 }; 43 44 return data; 45} 46 47function _glob() { 48 const data = require("glob"); 49 50 _glob = function () { 51 return data; 52 }; 53 54 return data; 55} 56 57function _path() { 58 const data = _interopRequireDefault(require("path")); 59 60 _path = function () { 61 return data; 62 }; 63 64 return data; 65} 66 67function _resolveFrom() { 68 const data = _interopRequireDefault(require("resolve-from")); 69 70 _resolveFrom = function () { 71 return data; 72 }; 73 74 return data; 75} 76 77function _semver() { 78 const data = _interopRequireDefault(require("semver")); 79 80 _semver = function () { 81 return data; 82 }; 83 84 return data; 85} 86 87function _slugify() { 88 const data = _interopRequireDefault(require("slugify")); 89 90 _slugify = function () { 91 return data; 92 }; 93 94 return data; 95} 96 97function _getConfig() { 98 const data = require("./getConfig"); 99 100 _getConfig = function () { 101 return data; 102 }; 103 104 return data; 105} 106 107function _getExpoSDKVersion() { 108 const data = require("./getExpoSDKVersion"); 109 110 _getExpoSDKVersion = function () { 111 return data; 112 }; 113 114 return data; 115} 116 117function _getFullName() { 118 const data = require("./getFullName"); 119 120 _getFullName = function () { 121 return data; 122 }; 123 124 return data; 125} 126 127function _withConfigPlugins() { 128 const data = require("./plugins/withConfigPlugins"); 129 130 _withConfigPlugins = function () { 131 return data; 132 }; 133 134 return data; 135} 136 137function _withInternal() { 138 const data = require("./plugins/withInternal"); 139 140 _withInternal = function () { 141 return data; 142 }; 143 144 return data; 145} 146 147function _resolvePackageJson() { 148 const data = require("./resolvePackageJson"); 149 150 _resolvePackageJson = function () { 151 return data; 152 }; 153 154 return data; 155} 156 157var _Config = require("./Config.types"); 158 159Object.keys(_Config).forEach(function (key) { 160 if (key === "default" || key === "__esModule") return; 161 if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; 162 if (key in exports && exports[key] === _Config[key]) return; 163 Object.defineProperty(exports, key, { 164 enumerable: true, 165 get: function () { 166 return _Config[key]; 167 } 168 }); 169}); 170 171function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 172 173/** 174 * If a config has an `expo` object then that will be used as the config. 175 * This method reduces out other top level values if an `expo` object exists. 176 * 177 * @param config Input config object to reduce 178 */ 179function reduceExpoObject(config) { 180 var _config$expo; 181 182 if (!config) return config === undefined ? null : config; 183 const { 184 mods, 185 ...expo 186 } = (_config$expo = config.expo) !== null && _config$expo !== void 0 ? _config$expo : config; 187 return { 188 expo, 189 mods 190 }; 191} 192/** 193 * Get all platforms that a project is currently capable of running. 194 * 195 * @param projectRoot 196 * @param exp 197 */ 198 199 200function getSupportedPlatforms(projectRoot) { 201 const platforms = []; 202 203 if (_resolveFrom().default.silent(projectRoot, 'react-native')) { 204 platforms.push('ios', 'android'); 205 } 206 207 if (_resolveFrom().default.silent(projectRoot, 'react-native-web')) { 208 platforms.push('web'); 209 } 210 211 return platforms; 212} 213/** 214 * Evaluate the config for an Expo project. 215 * If a function is exported from the `app.config.js` then a partial config will be passed as an argument. 216 * The partial config is composed from any existing app.json, and certain fields from the `package.json` like name and description. 217 * 218 * If options.isPublicConfig is true, the Expo config will include only public-facing options (omitting private keys). 219 * The resulting config should be suitable for hosting or embedding in a publicly readable location. 220 * 221 * **Example** 222 * ```js 223 * module.exports = function({ config }) { 224 * // mutate the config before returning it. 225 * config.slug = 'new slug' 226 * return { expo: config }; 227 * } 228 * ``` 229 * 230 * **Supports** 231 * - `app.config.ts` 232 * - `app.config.js` 233 * - `app.config.json` 234 * - `app.json` 235 * 236 * @param projectRoot the root folder containing all of your application code 237 * @param options enforce criteria for a project config 238 */ 239 240 241function getConfig(projectRoot, options = {}) { 242 const paths = getConfigFilePaths(projectRoot); 243 const rawStaticConfig = paths.staticConfigPath ? (0, _getConfig().getStaticConfig)(paths.staticConfigPath) : null; // For legacy reasons, always return an object. 244 245 const rootConfig = rawStaticConfig || {}; 246 const staticConfig = reduceExpoObject(rawStaticConfig) || {}; // Can only change the package.json location if an app.json or app.config.json exists 247 248 const [packageJson, packageJsonPath] = getPackageJsonAndPath(projectRoot); 249 250 function fillAndReturnConfig(config, dynamicConfigObjectType) { 251 const configWithDefaultValues = { ...ensureConfigHasDefaultValues({ 252 projectRoot, 253 exp: config.expo, 254 pkg: packageJson, 255 skipSDKVersionRequirement: options.skipSDKVersionRequirement, 256 paths, 257 packageJsonPath 258 }), 259 mods: config.mods, 260 dynamicConfigObjectType, 261 rootConfig, 262 dynamicConfigPath: paths.dynamicConfigPath, 263 staticConfigPath: paths.staticConfigPath 264 }; 265 266 if (options.isModdedConfig) { 267 var _config$mods; 268 269 // @ts-ignore: Add the mods back to the object. 270 configWithDefaultValues.exp.mods = (_config$mods = config.mods) !== null && _config$mods !== void 0 ? _config$mods : null; 271 } // Apply static json plugins, should be done after _internal 272 273 274 configWithDefaultValues.exp = (0, _withConfigPlugins().withConfigPlugins)(configWithDefaultValues.exp, !!options.skipPlugins); 275 276 if (!options.isModdedConfig) { 277 // @ts-ignore: Delete mods added by static plugins when they won't have a chance to be evaluated 278 delete configWithDefaultValues.exp.mods; 279 } 280 281 if (options.isPublicConfig) { 282 var _configWithDefaultVal, _configWithDefaultVal2, _configWithDefaultVal3, _configWithDefaultVal4; 283 284 // TODD(EvanBacon): Drop plugins array after it's been resolved. 285 // Remove internal values with references to user's file paths from the public config. 286 delete configWithDefaultValues.exp._internal; 287 288 if (configWithDefaultValues.exp.hooks) { 289 delete configWithDefaultValues.exp.hooks; 290 } 291 292 if ((_configWithDefaultVal = configWithDefaultValues.exp.ios) !== null && _configWithDefaultVal !== void 0 && _configWithDefaultVal.config) { 293 delete configWithDefaultValues.exp.ios.config; 294 } 295 296 if ((_configWithDefaultVal2 = configWithDefaultValues.exp.android) !== null && _configWithDefaultVal2 !== void 0 && _configWithDefaultVal2.config) { 297 delete configWithDefaultValues.exp.android.config; 298 } // These value will be overwritten when the manifest is being served from the host (i.e. not completely accurate). 299 // @ts-ignore: currentFullName not on type yet. 300 301 302 configWithDefaultValues.exp.currentFullName = (0, _getFullName().getFullName)(configWithDefaultValues.exp); // @ts-ignore: originalFullName not on type yet. 303 304 configWithDefaultValues.exp.originalFullName = (0, _getFullName().getFullName)(configWithDefaultValues.exp); 305 (_configWithDefaultVal3 = configWithDefaultValues.exp.updates) === null || _configWithDefaultVal3 === void 0 ? true : delete _configWithDefaultVal3.codeSigningCertificate; 306 (_configWithDefaultVal4 = configWithDefaultValues.exp.updates) === null || _configWithDefaultVal4 === void 0 ? true : delete _configWithDefaultVal4.codeSigningMetadata; 307 } 308 309 return configWithDefaultValues; 310 } // Fill in the static config 311 312 313 function getContextConfig(config) { 314 return ensureConfigHasDefaultValues({ 315 projectRoot, 316 exp: config.expo, 317 pkg: packageJson, 318 skipSDKVersionRequirement: true, 319 paths, 320 packageJsonPath 321 }).exp; 322 } 323 324 if (paths.dynamicConfigPath) { 325 // No app.config.json or app.json but app.config.js 326 const { 327 exportedObjectType, 328 config: rawDynamicConfig 329 } = (0, _getConfig().getDynamicConfig)(paths.dynamicConfigPath, { 330 projectRoot, 331 staticConfigPath: paths.staticConfigPath, 332 packageJsonPath, 333 config: getContextConfig(staticConfig) 334 }); // Allow for the app.config.js to `export default null;` 335 // Use `dynamicConfigPath` to detect if a dynamic config exists. 336 337 const dynamicConfig = reduceExpoObject(rawDynamicConfig) || {}; 338 return fillAndReturnConfig(dynamicConfig, exportedObjectType); 339 } // No app.config.js but json or no config 340 341 342 return fillAndReturnConfig(staticConfig || {}, null); 343} 344 345function getPackageJson(projectRoot) { 346 const [pkg] = getPackageJsonAndPath(projectRoot); 347 return pkg; 348} 349 350function getPackageJsonAndPath(projectRoot) { 351 const packageJsonPath = (0, _resolvePackageJson().getRootPackageJsonPath)(projectRoot); 352 return [_jsonFile().default.read(packageJsonPath), packageJsonPath]; 353} 354/** 355 * Get the static and dynamic config paths for a project. Also accounts for custom paths. 356 * 357 * @param projectRoot 358 */ 359 360 361function getConfigFilePaths(projectRoot) { 362 return { 363 dynamicConfigPath: getDynamicConfigFilePath(projectRoot), 364 staticConfigPath: getStaticConfigFilePath(projectRoot) 365 }; 366} 367 368function getDynamicConfigFilePath(projectRoot) { 369 for (const fileName of ['app.config.ts', 'app.config.js']) { 370 const configPath = _path().default.join(projectRoot, fileName); 371 372 if (_fs().default.existsSync(configPath)) { 373 return configPath; 374 } 375 } 376 377 return null; 378} 379 380function getStaticConfigFilePath(projectRoot) { 381 for (const fileName of ['app.config.json', 'app.json']) { 382 const configPath = _path().default.join(projectRoot, fileName); 383 384 if (_fs().default.existsSync(configPath)) { 385 return configPath; 386 } 387 } 388 389 return null; 390} 391/** 392 * Attempt to modify an Expo project config. 393 * This will only fully work if the project is using static configs only. 394 * Otherwise 'warn' | 'fail' will return with a message about why the config couldn't be updated. 395 * The potentially modified config object will be returned for testing purposes. 396 * 397 * @param projectRoot 398 * @param modifications modifications to make to an existing config 399 * @param readOptions options for reading the current config file 400 * @param writeOptions If true, the static config file will not be rewritten 401 */ 402 403 404async function modifyConfigAsync(projectRoot, modifications, readOptions = {}, writeOptions = {}) { 405 const config = getConfig(projectRoot, readOptions); 406 407 if (config.dynamicConfigPath) { 408 // We cannot automatically write to a dynamic config. 409 410 /* Currently we should just use the safest approach possible, informing the user that they'll need to manually modify their dynamic config. 411 if (config.staticConfigPath) { 412 // Both a dynamic and a static config exist. 413 if (config.dynamicConfigObjectType === 'function') { 414 // The dynamic config exports a function, this means it possibly extends the static config. 415 } else { 416 // Dynamic config ignores the static config, there isn't a reason to automatically write to it. 417 // Instead we should warn the user to add values to their dynamic config. 418 } 419 } 420 */ 421 return { 422 type: 'warn', 423 message: `Cannot automatically write to dynamic config at: ${_path().default.relative(projectRoot, config.dynamicConfigPath)}`, 424 config: null 425 }; 426 } else if (config.staticConfigPath) { 427 // Static with no dynamic config, this means we can append to the config automatically. 428 let outputConfig; // If the config has an expo object (app.json) then append the options to that object. 429 430 if (config.rootConfig.expo) { 431 outputConfig = { ...config.rootConfig, 432 expo: { ...config.rootConfig.expo, 433 ...modifications 434 } 435 }; 436 } else { 437 // Otherwise (app.config.json) just add the config modification to the top most level. 438 outputConfig = { ...config.rootConfig, 439 ...modifications 440 }; 441 } 442 443 if (!writeOptions.dryRun) { 444 await _jsonFile().default.writeAsync(config.staticConfigPath, outputConfig, { 445 json5: false 446 }); 447 } 448 449 return { 450 type: 'success', 451 config: outputConfig 452 }; 453 } 454 455 return { 456 type: 'fail', 457 message: 'No config exists', 458 config: null 459 }; 460} 461 462function ensureConfigHasDefaultValues({ 463 projectRoot, 464 exp, 465 pkg, 466 paths, 467 packageJsonPath, 468 skipSDKVersionRequirement = false 469}) { 470 var _exp$name, _exp$slug, _exp$version; 471 472 if (!exp) { 473 exp = {}; 474 } 475 476 exp = (0, _withInternal().withInternal)(exp, { 477 projectRoot, 478 ...(paths !== null && paths !== void 0 ? paths : {}), 479 packageJsonPath 480 }); // Defaults for package.json fields 481 482 const pkgName = typeof pkg.name === 'string' ? pkg.name : _path().default.basename(projectRoot); 483 const pkgVersion = typeof pkg.version === 'string' ? pkg.version : '1.0.0'; 484 const pkgWithDefaults = { ...pkg, 485 name: pkgName, 486 version: pkgVersion 487 }; // Defaults for app.json/app.config.js fields 488 489 const name = (_exp$name = exp.name) !== null && _exp$name !== void 0 ? _exp$name : pkgName; 490 const slug = (_exp$slug = exp.slug) !== null && _exp$slug !== void 0 ? _exp$slug : (0, _slugify().default)(name.toLowerCase()); 491 const version = (_exp$version = exp.version) !== null && _exp$version !== void 0 ? _exp$version : pkgVersion; 492 let description = exp.description; 493 494 if (!description && typeof pkg.description === 'string') { 495 description = pkg.description; 496 } 497 498 const expWithDefaults = { ...exp, 499 name, 500 slug, 501 version, 502 description 503 }; 504 let sdkVersion; 505 506 try { 507 sdkVersion = (0, _getExpoSDKVersion().getExpoSDKVersion)(projectRoot, expWithDefaults); 508 } catch (error) { 509 if (!skipSDKVersionRequirement) throw error; 510 } 511 512 let platforms = exp.platforms; 513 514 if (!platforms) { 515 platforms = getSupportedPlatforms(projectRoot); 516 } 517 518 return { 519 exp: { ...expWithDefaults, 520 sdkVersion, 521 platforms 522 }, 523 pkg: pkgWithDefaults 524 }; 525} 526 527const DEFAULT_BUILD_PATH = `web-build`; 528 529function getWebOutputPath(config = {}) { 530 var _expo$web, _expo$web$build; 531 532 if (process.env.WEBPACK_BUILD_OUTPUT_PATH) { 533 return process.env.WEBPACK_BUILD_OUTPUT_PATH; 534 } 535 536 const expo = config.expo || config || {}; 537 return (expo === null || expo === void 0 ? void 0 : (_expo$web = expo.web) === null || _expo$web === void 0 ? void 0 : (_expo$web$build = _expo$web.build) === null || _expo$web$build === void 0 ? void 0 : _expo$web$build.output) || DEFAULT_BUILD_PATH; 538} 539 540function getNameFromConfig(exp = {}) { 541 // For RN CLI support 542 const appManifest = exp.expo || exp; 543 const { 544 web = {} 545 } = appManifest; // rn-cli apps use a displayName value as well. 546 547 const appName = exp.displayName || appManifest.displayName || appManifest.name; 548 const webName = web.name || appName; 549 return { 550 appName, 551 webName 552 }; 553} 554 555function getDefaultTarget(projectRoot, exp) { 556 var _exp; 557 558 (_exp = exp) !== null && _exp !== void 0 ? _exp : exp = getConfig(projectRoot, { 559 skipSDKVersionRequirement: true 560 }).exp; // before SDK 37, always default to managed to preserve previous behavior 561 562 if (exp.sdkVersion && exp.sdkVersion !== 'UNVERSIONED' && _semver().default.lt(exp.sdkVersion, '37.0.0')) { 563 return 'managed'; 564 } 565 566 return isBareWorkflowProject(projectRoot) ? 'bare' : 'managed'; 567} 568 569function isBareWorkflowProject(projectRoot) { 570 const [pkg] = getPackageJsonAndPath(projectRoot); // TODO: Drop this 571 572 if (pkg.dependencies && pkg.dependencies.expokit) { 573 return false; 574 } 575 576 const xcodeprojFiles = (0, _glob().sync)('ios/**/*.xcodeproj', { 577 absolute: true, 578 cwd: projectRoot 579 }); 580 581 if (xcodeprojFiles.length) { 582 return true; 583 } 584 585 const gradleFiles = (0, _glob().sync)('android/**/*.gradle', { 586 absolute: true, 587 cwd: projectRoot 588 }); 589 590 if (gradleFiles.length) { 591 return true; 592 } 593 594 return false; 595} 596/** 597 * Return a useful name describing the project config. 598 * - dynamic: app.config.js 599 * - static: app.json 600 * - custom path app config relative to root folder 601 * - both: app.config.js or app.json 602 */ 603 604 605function getProjectConfigDescription(projectRoot) { 606 const paths = getConfigFilePaths(projectRoot); 607 return getProjectConfigDescriptionWithPaths(projectRoot, paths); 608} 609/** 610 * Returns a string describing the configurations used for the given project root. 611 * Will return null if no config is found. 612 * 613 * @param projectRoot 614 * @param projectConfig 615 */ 616 617 618function getProjectConfigDescriptionWithPaths(projectRoot, projectConfig) { 619 if (projectConfig.dynamicConfigPath) { 620 const relativeDynamicConfigPath = _path().default.relative(projectRoot, projectConfig.dynamicConfigPath); 621 622 if (projectConfig.staticConfigPath) { 623 return `${relativeDynamicConfigPath} or ${_path().default.relative(projectRoot, projectConfig.staticConfigPath)}`; 624 } 625 626 return relativeDynamicConfigPath; 627 } else if (projectConfig.staticConfigPath) { 628 return _path().default.relative(projectRoot, projectConfig.staticConfigPath); 629 } // If a config doesn't exist, our tooling will generate a static app.json 630 631 632 return 'app.json'; 633} 634//# sourceMappingURL=Config.js.map