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