1"use strict"; 2 3Object.defineProperty(exports, "__esModule", { 4 value: true 5}); 6exports.withBaseMod = withBaseMod; 7exports.withMod = withMod; 8function _chalk() { 9 const data = _interopRequireDefault(require("chalk")); 10 _chalk = function () { 11 return data; 12 }; 13 return data; 14} 15function _getenv() { 16 const data = require("getenv"); 17 _getenv = function () { 18 return data; 19 }; 20 return data; 21} 22function _errors() { 23 const data = require("../utils/errors"); 24 _errors = function () { 25 return data; 26 }; 27 return data; 28} 29function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 30const EXPO_DEBUG = (0, _getenv().boolish)('EXPO_DEBUG', false); 31/** 32 * Plugin to intercept execution of a given `mod` with the given `action`. 33 * If an action was already set on the given `config` config for `mod`, then it 34 * will be provided to the `action` as `nextMod` when it's evaluated, otherwise 35 * `nextMod` will be an identity function. 36 * 37 * @param config exported config 38 * @param platform platform to target (ios or android) 39 * @param mod name of the platform function to intercept 40 * @param skipEmptyMod should skip running the action if there is no existing mod to intercept 41 * @param saveToInternal should save the results to `_internal.modResults`, only enable this when the results are pure JSON. 42 * @param isProvider should provide data up to the other mods. 43 * @param action method to run on the mod when the config is compiled 44 */ 45function withBaseMod(config, { 46 platform, 47 mod, 48 action, 49 skipEmptyMod, 50 isProvider, 51 isIntrospective, 52 saveToInternal 53}) { 54 var _config$_internal$isD, _config$_internal; 55 if (!config.mods) { 56 config.mods = {}; 57 } 58 if (!config.mods[platform]) { 59 config.mods[platform] = {}; 60 } 61 let interceptedMod = config.mods[platform][mod]; 62 63 // No existing mod to intercept 64 if (!interceptedMod) { 65 if (skipEmptyMod) { 66 // Skip running the action 67 return config; 68 } 69 // Use a noop mod and continue 70 const noopMod = config => config; 71 interceptedMod = noopMod; 72 } 73 74 // Create a stack trace for debugging ahead of time 75 let debugTrace = ''; 76 // Use the possibly user defined value. Otherwise fallback to the env variable. 77 // We support the env variable because user mods won't have _internal defined in time. 78 const isDebug = (_config$_internal$isD = (_config$_internal = config._internal) === null || _config$_internal === void 0 ? void 0 : _config$_internal.isDebug) !== null && _config$_internal$isD !== void 0 ? _config$_internal$isD : EXPO_DEBUG; 79 if (isDebug) { 80 // Get a stack trace via the Error API 81 const stack = new Error().stack; 82 // Format the stack trace to create the debug log 83 debugTrace = getDebugPluginStackFromStackTrace(stack); 84 const modStack = _chalk().default.bold(`${platform}.${mod}`); 85 debugTrace = `${modStack}: ${debugTrace}`; 86 } 87 88 // Prevent adding multiple providers to a mod. 89 // Base mods that provide files ignore any incoming modResults and therefore shouldn't have provider mods as parents. 90 if (interceptedMod.isProvider) { 91 if (isProvider) { 92 throw new (_errors().PluginError)(`Cannot set provider mod for "${platform}.${mod}" because another is already being used.`, 'CONFLICTING_PROVIDER'); 93 } else { 94 throw new (_errors().PluginError)(`Cannot add mod to "${platform}.${mod}" because the provider has already been added. Provider must be the last mod added.`, 'INVALID_MOD_ORDER'); 95 } 96 } 97 async function interceptingMod({ 98 modRequest, 99 ...config 100 }) { 101 if (isDebug) { 102 // In debug mod, log the plugin stack in the order which they were invoked 103 console.log(debugTrace); 104 } 105 const results = await action({ 106 ...config, 107 modRequest: { 108 ...modRequest, 109 nextMod: interceptedMod 110 } 111 }); 112 if (saveToInternal) { 113 saveToInternalObject(results, platform, mod, results.modResults); 114 } 115 return results; 116 } 117 118 // Ensure this base mod is registered as the provider. 119 interceptingMod.isProvider = isProvider; 120 if (isIntrospective) { 121 // Register the mode as idempotent so introspection doesn't remove it. 122 interceptingMod.isIntrospective = isIntrospective; 123 } 124 config.mods[platform][mod] = interceptingMod; 125 return config; 126} 127function saveToInternalObject(config, platformName, modName, results) { 128 if (!config._internal) config._internal = {}; 129 if (!config._internal.modResults) config._internal.modResults = {}; 130 if (!config._internal.modResults[platformName]) config._internal.modResults[platformName] = {}; 131 config._internal.modResults[platformName][modName] = results; 132} 133function getDebugPluginStackFromStackTrace(stacktrace) { 134 if (!stacktrace) { 135 return ''; 136 } 137 const treeStackLines = []; 138 for (const line of stacktrace.split('\n')) { 139 const [first, second] = line.trim().split(' '); 140 if (first === 'at') { 141 treeStackLines.push(second); 142 } 143 } 144 const plugins = treeStackLines.map(first => { 145 var _ref, _first$match$1$trim, _first$match, _first$match$, _first$match2, _first$match2$; 146 // Match the first part of the stack trace against the plugin naming convention 147 // "with" followed by a capital letter. 148 return (_ref = (_first$match$1$trim = first === null || first === void 0 ? void 0 : (_first$match = first.match(/^(\bwith[A-Z].*?\b)/)) === null || _first$match === void 0 ? void 0 : (_first$match$ = _first$match[1]) === null || _first$match$ === void 0 ? void 0 : _first$match$.trim()) !== null && _first$match$1$trim !== void 0 ? _first$match$1$trim : first === null || first === void 0 ? void 0 : (_first$match2 = first.match(/\.(\bwith[A-Z].*?\b)/)) === null || _first$match2 === void 0 ? void 0 : (_first$match2$ = _first$match2[1]) === null || _first$match2$ === void 0 ? void 0 : _first$match2$.trim()) !== null && _ref !== void 0 ? _ref : null; 149 }).filter(Boolean).filter(plugin => { 150 // redundant as all debug logs are captured in withBaseMod 151 return !['withMod', 'withBaseMod', 'withExtendedMod'].includes(plugin); 152 }); 153 const commonPlugins = ['withPlugins', 'withRunOnce', 'withStaticPlugin']; 154 return plugins.reverse().map((pluginName, index) => { 155 // Base mods indicate a logical section. 156 if (pluginName.includes('BaseMod')) { 157 pluginName = _chalk().default.bold(pluginName); 158 } 159 // highlight dangerous mods 160 if (pluginName.toLowerCase().includes('dangerous')) { 161 pluginName = _chalk().default.red(pluginName); 162 } 163 if (index === 0) { 164 return _chalk().default.blue(pluginName); 165 } else if (commonPlugins.includes(pluginName)) { 166 // Common mod names often clutter up the logs, dim them out 167 return _chalk().default.dim(pluginName); 168 } 169 return pluginName; 170 }) 171 // Join the results: 172 // withAndroidExpoPlugins ➜ withPlugins ➜ withIcons ➜ withDangerousMod ➜ withMod 173 .join(' ➜ '); 174} 175 176/** 177 * Plugin to extend a mod function in the plugins config. 178 * 179 * @param config exported config 180 * @param platform platform to target (ios or android) 181 * @param mod name of the platform function to extend 182 * @param action method to run on the mod when the config is compiled 183 */ 184function withMod(config, { 185 platform, 186 mod, 187 action 188}) { 189 return withBaseMod(config, { 190 platform, 191 mod, 192 isProvider: false, 193 async action({ 194 modRequest: { 195 nextMod, 196 ...modRequest 197 }, 198 modResults, 199 ...config 200 }) { 201 const results = await action({ 202 modRequest, 203 modResults: modResults, 204 ...config 205 }); 206 return nextMod(results); 207 } 208 }); 209} 210//# sourceMappingURL=withMod.js.map