1"use strict"; 2 3Object.defineProperty(exports, "__esModule", { 4 value: true 5}); 6exports.compileModsAsync = compileModsAsync; 7exports.evalModsAsync = evalModsAsync; 8exports.withDefaultBaseMods = withDefaultBaseMods; 9exports.withIntrospectionBaseMods = withIntrospectionBaseMods; 10function _debug() { 11 const data = _interopRequireDefault(require("debug")); 12 _debug = function () { 13 return data; 14 }; 15 return data; 16} 17function _path() { 18 const data = _interopRequireDefault(require("path")); 19 _path = function () { 20 return data; 21 }; 22 return data; 23} 24function _Xcodeproj() { 25 const data = require("../ios/utils/Xcodeproj"); 26 _Xcodeproj = function () { 27 return data; 28 }; 29 return data; 30} 31function _errors() { 32 const data = require("../utils/errors"); 33 _errors = function () { 34 return data; 35 }; 36 return data; 37} 38function Warnings() { 39 const data = _interopRequireWildcard(require("../utils/warnings")); 40 Warnings = function () { 41 return data; 42 }; 43 return data; 44} 45function _createBaseMod() { 46 const data = require("./createBaseMod"); 47 _createBaseMod = function () { 48 return data; 49 }; 50 return data; 51} 52function _withAndroidBaseMods() { 53 const data = require("./withAndroidBaseMods"); 54 _withAndroidBaseMods = function () { 55 return data; 56 }; 57 return data; 58} 59function _withIosBaseMods() { 60 const data = require("./withIosBaseMods"); 61 _withIosBaseMods = function () { 62 return data; 63 }; 64 return data; 65} 66function _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); } 67function _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; } 68function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 69const debug = (0, _debug().default)('expo:config-plugins:mod-compiler'); 70function withDefaultBaseMods(config, props = {}) { 71 config = (0, _withIosBaseMods().withIosBaseMods)(config, props); 72 config = (0, _withAndroidBaseMods().withAndroidBaseMods)(config, props); 73 return config; 74} 75 76/** 77 * Get a prebuild config that safely evaluates mods without persisting any changes to the file system. 78 * Currently this only supports infoPlist, entitlements, androidManifest, strings, gradleProperties, and expoPlist mods. 79 * This plugin should be evaluated directly: 80 */ 81function withIntrospectionBaseMods(config, props = {}) { 82 config = (0, _withIosBaseMods().withIosBaseMods)(config, { 83 saveToInternal: true, 84 // This writing optimization can be skipped since we never write in introspection mode. 85 // Including empty mods will ensure that all mods get introspected. 86 skipEmptyMod: false, 87 ...props 88 }); 89 config = (0, _withAndroidBaseMods().withAndroidBaseMods)(config, { 90 saveToInternal: true, 91 skipEmptyMod: false, 92 ...props 93 }); 94 if (config.mods) { 95 // Remove all mods that don't have an introspection base mod, for instance `dangerous` mods. 96 for (const platform of Object.keys(config.mods)) { 97 // const platformPreserve = preserve[platform]; 98 for (const key of Object.keys(config.mods[platform] || {})) { 99 var _config$mods$platform, _config$mods$platform2; 100 // @ts-ignore 101 if (!((_config$mods$platform = config.mods[platform]) !== null && _config$mods$platform !== void 0 && (_config$mods$platform2 = _config$mods$platform[key]) !== null && _config$mods$platform2 !== void 0 && _config$mods$platform2.isIntrospective)) { 102 var _config$mods$platform3; 103 debug(`removing non-idempotent mod: ${platform}.${key}`); 104 // @ts-ignore 105 (_config$mods$platform3 = config.mods[platform]) === null || _config$mods$platform3 === void 0 ? true : delete _config$mods$platform3[key]; 106 } 107 } 108 } 109 } 110 return config; 111} 112 113/** 114 * 115 * @param projectRoot 116 * @param config 117 */ 118async function compileModsAsync(config, props) { 119 if (props.introspect === true) { 120 config = withIntrospectionBaseMods(config); 121 } else { 122 config = withDefaultBaseMods(config); 123 } 124 return await evalModsAsync(config, props); 125} 126function sortMods(commands, order) { 127 const allKeys = commands.map(([key]) => key); 128 const completeOrder = [...new Set([...order, ...allKeys])]; 129 const sorted = []; 130 while (completeOrder.length) { 131 const group = completeOrder.shift(); 132 const commandSet = commands.find(([key]) => key === group); 133 if (commandSet) { 134 sorted.push(commandSet); 135 } 136 } 137 return sorted; 138} 139function getRawClone({ 140 mods, 141 ...config 142}) { 143 // Configs should be fully serializable, so we can clone them without worrying about 144 // the mods. 145 return Object.freeze(JSON.parse(JSON.stringify(config))); 146} 147const orders = { 148 ios: [ 149 // dangerous runs first 150 'dangerous', 151 // run the XcodeProject mod second because many plugins attempt to read from it. 152 'xcodeproj'], 153 android: ['dangerous'] 154}; 155/** 156 * A generic plugin compiler. 157 * 158 * @param config 159 */ 160async function evalModsAsync(config, { 161 projectRoot, 162 introspect, 163 platforms, 164 /** 165 * Throw errors when mods are missing providers. 166 * @default true 167 */ 168 assertMissingModProviders 169}) { 170 const modRawConfig = getRawClone(config); 171 for (const [platformName, platform] of Object.entries((_config$mods = config.mods) !== null && _config$mods !== void 0 ? _config$mods : {})) { 172 var _config$mods; 173 if (platforms && !platforms.includes(platformName)) { 174 debug(`skip platform: ${platformName}`); 175 continue; 176 } 177 let entries = Object.entries(platform); 178 if (entries.length) { 179 var _orders$platformName; 180 // Move dangerous item to the first position if it exists, this ensures that all dangerous code runs first. 181 entries = sortMods(entries, (_orders$platformName = orders[platformName]) !== null && _orders$platformName !== void 0 ? _orders$platformName : ['dangerous']); 182 debug(`run in order: ${entries.map(([name]) => name).join(', ')}`); 183 const platformProjectRoot = _path().default.join(projectRoot, platformName); 184 const projectName = platformName === 'ios' ? (0, _Xcodeproj().getHackyProjectName)(projectRoot, config) : undefined; 185 for (const [modName, mod] of entries) { 186 const modRequest = { 187 projectRoot, 188 projectName, 189 platformProjectRoot, 190 platform: platformName, 191 modName, 192 introspect: !!introspect 193 }; 194 if (!mod.isProvider) { 195 // In strict mode, throw an error. 196 const errorMessage = `Initial base modifier for "${platformName}.${modName}" is not a provider and therefore will not provide modResults to child mods`; 197 if (assertMissingModProviders !== false) { 198 throw new (_errors().PluginError)(errorMessage, 'MISSING_PROVIDER'); 199 } else { 200 Warnings().addWarningForPlatform(platformName, `${platformName}.${modName}`, `Skipping: Initial base modifier for "${platformName}.${modName}" is not a provider and therefore will not provide modResults to child mods. This may be due to an outdated version of Expo CLI.`); 201 // In loose mode, just skip the mod entirely. 202 continue; 203 } 204 } 205 const results = await mod({ 206 ...config, 207 modResults: null, 208 modRequest, 209 modRawConfig 210 }); 211 212 // Sanity check to help locate non compliant mods. 213 config = (0, _createBaseMod().assertModResults)(results, platformName, modName); 214 // @ts-ignore: `modResults` is added for modifications 215 delete config.modResults; 216 // @ts-ignore: `modRequest` is added for modifications 217 delete config.modRequest; 218 // @ts-ignore: `modRawConfig` is added for modifications 219 delete config.modRawConfig; 220 } 221 } 222 } 223 return config; 224} 225//# sourceMappingURL=mod-compiler.js.map