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