xref: /expo/packages/@expo/config/build/evalConfig.js (revision dfd15ebd)
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4  value: true
5});
6exports.evalConfig = evalConfig;
7exports.resolveConfigExport = resolveConfigExport;
8
9function _fs() {
10  const data = require("fs");
11
12  _fs = function () {
13    return data;
14  };
15
16  return data;
17}
18
19function _requireFromString() {
20  const data = _interopRequireDefault(require("require-from-string"));
21
22  _requireFromString = function () {
23    return data;
24  };
25
26  return data;
27}
28
29function _sucrase() {
30  const data = require("sucrase");
31
32  _sucrase = function () {
33    return data;
34  };
35
36  return data;
37}
38
39function _Errors() {
40  const data = require("./Errors");
41
42  _Errors = function () {
43    return data;
44  };
45
46  return data;
47}
48
49function _Serialize() {
50  const data = require("./Serialize");
51
52  _Serialize = function () {
53    return data;
54  };
55
56  return data;
57}
58
59function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
60
61/**
62 * Transpile and evaluate the dynamic config object.
63 * This method is shared between the standard reading method in getConfig, and the headless script.
64 *
65 * @param options configFile path to the dynamic app.config.*, request to send to the dynamic config if it exports a function.
66 * @returns the serialized and evaluated config along with the exported object type (object or function).
67 */
68function evalConfig(configFile, request) {
69  const contents = (0, _fs().readFileSync)(configFile, 'utf8');
70  let result;
71
72  try {
73    const {
74      code
75    } = (0, _sucrase().transform)(contents, {
76      filePath: configFile,
77      transforms: ['typescript', 'imports']
78    });
79    result = (0, _requireFromString().default)(code, configFile);
80  } catch (error) {
81    const location = extractLocationFromSyntaxError(error); // Apply a code frame preview to the error if possible, sucrase doesn't do this by default.
82
83    if (location) {
84      const {
85        codeFrameColumns
86      } = require('@babel/code-frame');
87
88      const codeFrame = codeFrameColumns(contents, {
89        start: error.loc
90      }, {
91        highlightCode: true
92      });
93      error.codeFrame = codeFrame;
94      error.message += `\n${codeFrame}`;
95    } else {
96      const importantStack = extractImportantStackFromNodeError(error);
97
98      if (importantStack) {
99        error.message += `\n${importantStack}`;
100      }
101    }
102
103    throw error;
104  }
105
106  return resolveConfigExport(result, configFile, request);
107}
108
109function extractLocationFromSyntaxError(error) {
110  // sucrase provides the `loc` object
111  if (error.loc) {
112    return error.loc;
113  } // `SyntaxError`s provide the `lineNumber` and `columnNumber` properties
114
115
116  if ('lineNumber' in error && 'columnNumber' in error) {
117    return {
118      line: error.lineNumber,
119      column: error.columnNumber
120    };
121  }
122
123  return null;
124} // These kinda errors often come from syntax errors in files that were imported by the main file.
125// An example is a module that includes an import statement.
126
127
128function extractImportantStackFromNodeError(error) {
129  if (isSyntaxError(error)) {
130    var _error$stack;
131
132    const traces = (_error$stack = error.stack) === null || _error$stack === void 0 ? void 0 : _error$stack.split('\n').filter(line => !line.startsWith('    at '));
133    if (!traces) return null; // Remove redundant line
134
135    if (traces[traces.length - 1].startsWith('SyntaxError:')) {
136      traces.pop();
137    }
138
139    return traces.join('\n');
140  }
141
142  return null;
143}
144
145function isSyntaxError(error) {
146  return error instanceof SyntaxError || error.constructor.name === 'SyntaxError';
147}
148/**
149 * - Resolve the exported contents of an Expo config (be it default or module.exports)
150 * - Assert no promise exports
151 * - Return config type
152 * - Serialize config
153 *
154 * @param result
155 * @param configFile
156 * @param request
157 */
158
159
160function resolveConfigExport(result, configFile, request) {
161  var _result;
162
163  if (result.default != null) {
164    result = result.default;
165  }
166
167  const exportedObjectType = typeof result;
168
169  if (typeof result === 'function') {
170    result = result(request);
171  }
172
173  if (result instanceof Promise) {
174    throw new (_Errors().ConfigError)(`Config file ${configFile} cannot return a Promise.`, 'INVALID_CONFIG');
175  } // If the expo object exists, ignore all other values.
176
177
178  if ((_result = result) !== null && _result !== void 0 && _result.expo) {
179    result = (0, _Serialize().serializeSkippingMods)(result.expo);
180  } else {
181    result = (0, _Serialize().serializeSkippingMods)(result);
182  }
183
184  return {
185    config: result,
186    exportedObjectType
187  };
188}
189//# sourceMappingURL=evalConfig.js.map