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