1082815dcSEvan Bacon"use strict";
2082815dcSEvan Bacon
3082815dcSEvan BaconObject.defineProperty(exports, "__esModule", {
4082815dcSEvan Bacon  value: true
5082815dcSEvan Bacon});
6082815dcSEvan Baconexports.withBaseMod = withBaseMod;
7082815dcSEvan Baconexports.withMod = withMod;
8082815dcSEvan Baconfunction _chalk() {
9082815dcSEvan Bacon  const data = _interopRequireDefault(require("chalk"));
10082815dcSEvan Bacon  _chalk = function () {
11082815dcSEvan Bacon    return data;
12082815dcSEvan Bacon  };
13082815dcSEvan Bacon  return data;
14082815dcSEvan Bacon}
15082815dcSEvan Baconfunction _getenv() {
16082815dcSEvan Bacon  const data = require("getenv");
17082815dcSEvan Bacon  _getenv = function () {
18082815dcSEvan Bacon    return data;
19082815dcSEvan Bacon  };
20082815dcSEvan Bacon  return data;
21082815dcSEvan Bacon}
22082815dcSEvan Baconfunction _errors() {
23082815dcSEvan Bacon  const data = require("../utils/errors");
24082815dcSEvan Bacon  _errors = function () {
25082815dcSEvan Bacon    return data;
26082815dcSEvan Bacon  };
27082815dcSEvan Bacon  return data;
28082815dcSEvan Bacon}
29082815dcSEvan Baconfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
30082815dcSEvan Baconconst EXPO_DEBUG = (0, _getenv().boolish)('EXPO_DEBUG', false);
31082815dcSEvan Bacon/**
32082815dcSEvan Bacon * Plugin to intercept execution of a given `mod` with the given `action`.
33082815dcSEvan Bacon * If an action was already set on the given `config` config for `mod`, then it
34082815dcSEvan Bacon * will be provided to the `action` as `nextMod` when it's evaluated, otherwise
35082815dcSEvan Bacon * `nextMod` will be an identity function.
36082815dcSEvan Bacon *
37082815dcSEvan Bacon * @param config exported config
38082815dcSEvan Bacon * @param platform platform to target (ios or android)
39082815dcSEvan Bacon * @param mod name of the platform function to intercept
40082815dcSEvan Bacon * @param skipEmptyMod should skip running the action if there is no existing mod to intercept
41082815dcSEvan Bacon * @param saveToInternal should save the results to `_internal.modResults`, only enable this when the results are pure JSON.
42082815dcSEvan Bacon * @param isProvider should provide data up to the other mods.
43082815dcSEvan Bacon * @param action method to run on the mod when the config is compiled
44082815dcSEvan Bacon */
45082815dcSEvan Baconfunction withBaseMod(config, {
46082815dcSEvan Bacon  platform,
47082815dcSEvan Bacon  mod,
48082815dcSEvan Bacon  action,
49082815dcSEvan Bacon  skipEmptyMod,
50082815dcSEvan Bacon  isProvider,
51082815dcSEvan Bacon  isIntrospective,
52082815dcSEvan Bacon  saveToInternal
53082815dcSEvan Bacon}) {
54082815dcSEvan Bacon  var _config$_internal$isD, _config$_internal;
55082815dcSEvan Bacon  if (!config.mods) {
56082815dcSEvan Bacon    config.mods = {};
57082815dcSEvan Bacon  }
58082815dcSEvan Bacon  if (!config.mods[platform]) {
59082815dcSEvan Bacon    config.mods[platform] = {};
60082815dcSEvan Bacon  }
61*ee216927STomasz Sapeta  let interceptedMod = config.mods[platform][mod];
62082815dcSEvan Bacon
63*ee216927STomasz Sapeta  // No existing mod to intercept
64082815dcSEvan Bacon  if (!interceptedMod) {
65082815dcSEvan Bacon    if (skipEmptyMod) {
66082815dcSEvan Bacon      // Skip running the action
67082815dcSEvan Bacon      return config;
68*ee216927STomasz Sapeta    }
69*ee216927STomasz Sapeta    // Use a noop mod and continue
70082815dcSEvan Bacon    const noopMod = config => config;
71082815dcSEvan Bacon    interceptedMod = noopMod;
72*ee216927STomasz Sapeta  }
73082815dcSEvan Bacon
74*ee216927STomasz Sapeta  // Create a stack trace for debugging ahead of time
75*ee216927STomasz Sapeta  let debugTrace = '';
76*ee216927STomasz Sapeta  // Use the possibly user defined value. Otherwise fallback to the env variable.
77082815dcSEvan Bacon  // We support the env variable because user mods won't have _internal defined in time.
78082815dcSEvan Bacon  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;
79082815dcSEvan Bacon  if (isDebug) {
80082815dcSEvan Bacon    // Get a stack trace via the Error API
81*ee216927STomasz Sapeta    const stack = new Error().stack;
82*ee216927STomasz Sapeta    // Format the stack trace to create the debug log
83082815dcSEvan Bacon    debugTrace = getDebugPluginStackFromStackTrace(stack);
84082815dcSEvan Bacon    const modStack = _chalk().default.bold(`${platform}.${mod}`);
85082815dcSEvan Bacon    debugTrace = `${modStack}: ${debugTrace}`;
86*ee216927STomasz Sapeta  }
87*ee216927STomasz Sapeta
88*ee216927STomasz Sapeta  // Prevent adding multiple providers to a mod.
89082815dcSEvan Bacon  // Base mods that provide files ignore any incoming modResults and therefore shouldn't have provider mods as parents.
90082815dcSEvan Bacon  if (interceptedMod.isProvider) {
91082815dcSEvan Bacon    if (isProvider) {
92082815dcSEvan Bacon      throw new (_errors().PluginError)(`Cannot set provider mod for "${platform}.${mod}" because another is already being used.`, 'CONFLICTING_PROVIDER');
93082815dcSEvan Bacon    } else {
94082815dcSEvan Bacon      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');
95082815dcSEvan Bacon    }
96082815dcSEvan Bacon  }
97082815dcSEvan Bacon  async function interceptingMod({
98082815dcSEvan Bacon    modRequest,
99082815dcSEvan Bacon    ...config
100082815dcSEvan Bacon  }) {
101082815dcSEvan Bacon    if (isDebug) {
102082815dcSEvan Bacon      // In debug mod, log the plugin stack in the order which they were invoked
103082815dcSEvan Bacon      console.log(debugTrace);
104082815dcSEvan Bacon    }
105*ee216927STomasz Sapeta    const results = await action({
106*ee216927STomasz Sapeta      ...config,
107*ee216927STomasz Sapeta      modRequest: {
108*ee216927STomasz Sapeta        ...modRequest,
109082815dcSEvan Bacon        nextMod: interceptedMod
110082815dcSEvan Bacon      }
111082815dcSEvan Bacon    });
112082815dcSEvan Bacon    if (saveToInternal) {
113082815dcSEvan Bacon      saveToInternalObject(results, platform, mod, results.modResults);
114082815dcSEvan Bacon    }
115082815dcSEvan Bacon    return results;
116*ee216927STomasz Sapeta  }
117082815dcSEvan Bacon
118*ee216927STomasz Sapeta  // Ensure this base mod is registered as the provider.
119082815dcSEvan Bacon  interceptingMod.isProvider = isProvider;
120082815dcSEvan Bacon  if (isIntrospective) {
121082815dcSEvan Bacon    // Register the mode as idempotent so introspection doesn't remove it.
122082815dcSEvan Bacon    interceptingMod.isIntrospective = isIntrospective;
123082815dcSEvan Bacon  }
124082815dcSEvan Bacon  config.mods[platform][mod] = interceptingMod;
125082815dcSEvan Bacon  return config;
126082815dcSEvan Bacon}
127082815dcSEvan Baconfunction saveToInternalObject(config, platformName, modName, results) {
128082815dcSEvan Bacon  if (!config._internal) config._internal = {};
129082815dcSEvan Bacon  if (!config._internal.modResults) config._internal.modResults = {};
130082815dcSEvan Bacon  if (!config._internal.modResults[platformName]) config._internal.modResults[platformName] = {};
131082815dcSEvan Bacon  config._internal.modResults[platformName][modName] = results;
132082815dcSEvan Bacon}
133082815dcSEvan Baconfunction getDebugPluginStackFromStackTrace(stacktrace) {
134082815dcSEvan Bacon  if (!stacktrace) {
135082815dcSEvan Bacon    return '';
136082815dcSEvan Bacon  }
137082815dcSEvan Bacon  const treeStackLines = [];
138082815dcSEvan Bacon  for (const line of stacktrace.split('\n')) {
139082815dcSEvan Bacon    const [first, second] = line.trim().split(' ');
140082815dcSEvan Bacon    if (first === 'at') {
141082815dcSEvan Bacon      treeStackLines.push(second);
142082815dcSEvan Bacon    }
143082815dcSEvan Bacon  }
144082815dcSEvan Bacon  const plugins = treeStackLines.map(first => {
145082815dcSEvan Bacon    var _ref, _first$match$1$trim, _first$match, _first$match$, _first$match2, _first$match2$;
146082815dcSEvan Bacon    // Match the first part of the stack trace against the plugin naming convention
147082815dcSEvan Bacon    // "with" followed by a capital letter.
148082815dcSEvan Bacon    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;
149082815dcSEvan Bacon  }).filter(Boolean).filter(plugin => {
150082815dcSEvan Bacon    // redundant as all debug logs are captured in withBaseMod
151082815dcSEvan Bacon    return !['withMod', 'withBaseMod', 'withExtendedMod'].includes(plugin);
152082815dcSEvan Bacon  });
153082815dcSEvan Bacon  const commonPlugins = ['withPlugins', 'withRunOnce', 'withStaticPlugin'];
154082815dcSEvan Bacon  return plugins.reverse().map((pluginName, index) => {
155082815dcSEvan Bacon    // Base mods indicate a logical section.
156082815dcSEvan Bacon    if (pluginName.includes('BaseMod')) {
157082815dcSEvan Bacon      pluginName = _chalk().default.bold(pluginName);
158*ee216927STomasz Sapeta    }
159*ee216927STomasz Sapeta    // highlight dangerous mods
160082815dcSEvan Bacon    if (pluginName.toLowerCase().includes('dangerous')) {
161082815dcSEvan Bacon      pluginName = _chalk().default.red(pluginName);
162082815dcSEvan Bacon    }
163082815dcSEvan Bacon    if (index === 0) {
164082815dcSEvan Bacon      return _chalk().default.blue(pluginName);
165082815dcSEvan Bacon    } else if (commonPlugins.includes(pluginName)) {
166082815dcSEvan Bacon      // Common mod names often clutter up the logs, dim them out
167082815dcSEvan Bacon      return _chalk().default.dim(pluginName);
168082815dcSEvan Bacon    }
169082815dcSEvan Bacon    return pluginName;
170*ee216927STomasz Sapeta  })
171*ee216927STomasz Sapeta  // Join the results:
172082815dcSEvan Bacon  // withAndroidExpoPlugins ➜ withPlugins ➜ withIcons ➜ withDangerousMod ➜ withMod
173082815dcSEvan Bacon  .join(' ➜ ');
174082815dcSEvan Bacon}
175*ee216927STomasz Sapeta
176082815dcSEvan Bacon/**
177082815dcSEvan Bacon * Plugin to extend a mod function in the plugins config.
178082815dcSEvan Bacon *
179082815dcSEvan Bacon * @param config exported config
180082815dcSEvan Bacon * @param platform platform to target (ios or android)
181082815dcSEvan Bacon * @param mod name of the platform function to extend
182082815dcSEvan Bacon * @param action method to run on the mod when the config is compiled
183082815dcSEvan Bacon */
184082815dcSEvan Baconfunction withMod(config, {
185082815dcSEvan Bacon  platform,
186082815dcSEvan Bacon  mod,
187082815dcSEvan Bacon  action
188082815dcSEvan Bacon}) {
189082815dcSEvan Bacon  return withBaseMod(config, {
190082815dcSEvan Bacon    platform,
191082815dcSEvan Bacon    mod,
192082815dcSEvan Bacon    isProvider: false,
193082815dcSEvan Bacon    async action({
194082815dcSEvan Bacon      modRequest: {
195082815dcSEvan Bacon        nextMod,
196082815dcSEvan Bacon        ...modRequest
197082815dcSEvan Bacon      },
198082815dcSEvan Bacon      modResults,
199082815dcSEvan Bacon      ...config
200082815dcSEvan Bacon    }) {
201082815dcSEvan Bacon      const results = await action({
202082815dcSEvan Bacon        modRequest,
203082815dcSEvan Bacon        modResults: modResults,
204082815dcSEvan Bacon        ...config
205082815dcSEvan Bacon      });
206082815dcSEvan Bacon      return nextMod(results);
207082815dcSEvan Bacon    }
208082815dcSEvan Bacon  });
209082815dcSEvan Bacon}
210082815dcSEvan Bacon//# sourceMappingURL=withMod.js.map