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