1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4  value: true
5});
6exports.createMultiRuleTransformer = createMultiRuleTransformer;
7exports.loaders = void 0;
8
9function _chalk() {
10  const data = _interopRequireDefault(require("chalk"));
11
12  _chalk = function () {
13    return data;
14  };
15
16  return data;
17}
18
19function _debug() {
20  const data = _interopRequireDefault(require("debug"));
21
22  _debug = function () {
23    return data;
24  };
25
26  return data;
27}
28
29function _resolveFrom() {
30  const data = _interopRequireDefault(require("resolve-from"));
31
32  _resolveFrom = function () {
33    return data;
34  };
35
36  return data;
37}
38
39function _generateFunctionMap() {
40  const data = require("./generateFunctionMap");
41
42  _generateFunctionMap = function () {
43    return data;
44  };
45
46  return data;
47}
48
49function _getBabelConfig() {
50  const data = require("./getBabelConfig");
51
52  _getBabelConfig = function () {
53    return data;
54  };
55
56  return data;
57}
58
59function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
60
61// Copyright 2021-present 650 Industries (Expo). All rights reserved.
62const debug = (0, _debug().default)('expo:metro:exotic-babel-transformer');
63let babelCore;
64
65function getBabelCoreFromProject(projectRoot) {
66  if (babelCore) return babelCore;
67  babelCore = require((0, _resolveFrom().default)(projectRoot, '@babel/core'));
68  return babelCore;
69}
70
71let babelParser;
72
73function getBabelParserFromProject(projectRoot) {
74  if (babelParser) return babelParser;
75  babelParser = require((0, _resolveFrom().default)(projectRoot, '@babel/parser'));
76  return babelParser;
77}
78
79function sucrase(args, {
80  transforms
81}) {
82  const {
83    src,
84    filename,
85    options: {
86      dev
87    }
88  } = args;
89
90  const {
91    transform
92  } = require('sucrase');
93
94  const results = transform(src, {
95    filePath: filename,
96    production: !dev,
97    transforms
98  });
99  return {
100    code: results.code,
101    functionMap: null
102  };
103}
104
105const getExpensiveSucraseTransforms = filename => ['jsx', 'imports', /\.tsx?$/.test(filename) ? 'typescript' : 'flow'];
106
107function parseAst(projectRoot, sourceCode) {
108  const babylon = getBabelParserFromProject(projectRoot);
109  return babylon.parse(sourceCode, {
110    sourceType: 'unambiguous'
111  });
112}
113
114/** Create a transformer that emulates Webpack's loader system. */
115function createMultiRuleTransformer({
116  getRuleType,
117  rules
118}) {
119  // const warnings: string[] = [];
120  return function transform(args) {
121    const {
122      filename,
123      options
124    } = args;
125    const OLD_BABEL_ENV = process.env.BABEL_ENV;
126    process.env.BABEL_ENV = options !== null && options !== void 0 && options.dev ? 'development' : process.env.BABEL_ENV || 'production';
127
128    try {
129      const ruleType = getRuleType(args);
130
131      for (const rule of rules) {
132        // optimization for checking node modules
133        if (rule.type && rule.type !== ruleType) {
134          continue;
135        }
136
137        const isMatched = typeof rule.test === 'function' ? rule.test(args) : rule.test.test(args.filename);
138
139        if (isMatched) {
140          const results = rule.transform(args); // @ts-ignore: Add extra property for testing
141
142          results._ruleName = rule.name; // Perform a basic parse if none exists, this enables us to control the output, but only if it changed.
143
144          if (results.code && !results.ast) {
145            // Parse AST with babel otherwise Metro transformer will throw away the returned results.
146            results.ast = parseAst(options === null || options === void 0 ? void 0 : options.projectRoot, results.code);
147          } // TODO: Suboptimal warnings
148          // if (rule.warn) {
149          //   const matchName =
150          //     filename.match(/node_modules\/((:?@[\w\d-]+\/[\w\d-]+)|(:?[\w\d-]+))\/?/)?.[1] ??
151          //     filename;
152          //   if (matchName && !warnings.includes(matchName)) {
153          //     warnings.push(matchName);
154          //     console.warn(chalk.yellow.bold`warn `, matchName);
155          //     console.warn(
156          //       chalk.yellow`untranspiled module is potentially causing bundler slowdown, using modules that support commonjs will make your dev server much faster.`
157          //     );
158          //   }
159          // }
160
161
162          return results;
163        }
164      }
165
166      throw new Error('no loader rule to handle file: ' + filename);
167    } finally {
168      if (OLD_BABEL_ENV) {
169        process.env.BABEL_ENV = OLD_BABEL_ENV;
170      }
171    }
172  };
173}
174
175const loaders = {
176  // Perform the standard, and most expensive transpilation sequence.
177  app(args) {
178    debug('app:', args.filename);
179    const {
180      filename,
181      options,
182      src,
183      plugins
184    } = args;
185    const babelConfig = {
186      // ES modules require sourceType='module' but OSS may not always want that
187      sourceType: 'unambiguous',
188      ...(0, _getBabelConfig().getBabelConfig)(filename, options, plugins),
189      // Variables that are exposed to the user's babel preset.
190      caller: {
191        name: 'metro',
192        platform: options.platform
193      },
194      ast: true
195    }; // Surface a warning function so babel linters can be used.
196
197    Object.defineProperty(babelConfig.caller, 'onWarning', {
198      enumerable: false,
199      writable: false,
200      value: babelConfig.caller.onWarning = function (msg) {
201        // Format the file path first so users know where the warning came from.
202        console.warn(_chalk().default.bold.yellow`warn ` + args.filename);
203        console.warn(msg);
204      }
205    });
206    const {
207      parseSync,
208      transformFromAstSync
209    } = getBabelCoreFromProject(options.projectRoot);
210    const sourceAst = parseSync(src, babelConfig); // Should never happen.
211
212    if (!sourceAst) return {
213      ast: null
214    };
215    const result = transformFromAstSync(sourceAst, src, babelConfig); // TODO: Disable by default
216
217    const functionMap = (0, _generateFunctionMap().generateFunctionMap)(options.projectRoot, sourceAst, {
218      filename
219    }); // The result from `transformFromAstSync` can be null (if the file is ignored)
220
221    if (!result) {
222      return {
223        ast: null,
224        functionMap
225      };
226    }
227
228    return {
229      ast: result.ast,
230      functionMap
231    };
232  },
233
234  // Transpile react-native with sucrase.
235  reactNativeModule(args) {
236    debug('rn:', args.filename);
237    return sucrase(args, {
238      transforms: ['jsx', 'flow', 'imports']
239    });
240  },
241
242  // Transpile expo modules with sucrase.
243  expoModule(args) {
244    debug('expo:', args.filename); // TODO: Fix all expo packages
245
246    return sucrase(args, {
247      transforms: ['imports', // TODO: fix expo-processing, expo/vector-icons
248      /(expo-processing|expo\/vector-icons)/.test(args.filename) && 'jsx', // TODO: fix expo-asset-utils
249      /(expo-asset-utils)/.test(args.filename) && 'flow'].filter(Boolean)
250    });
251  },
252
253  // Transpile known community modules with the most expensive sucrase
254  untranspiledModule(args) {
255    debug('known issues:', args.filename);
256    return sucrase(args, {
257      transforms: getExpensiveSucraseTransforms(args.filename)
258    });
259  },
260
261  // Pass all modules through without transpiling them.
262  passthroughModule(args) {
263    const {
264      filename,
265      options,
266      src
267    } = args;
268    debug('passthrough:', filename); // Perform a basic ast parse, this doesn't matter since the worker will parse and ignore anyways.
269
270    const ast = parseAst(options.projectRoot, src); // TODO: Disable by default
271
272    const functionMap = (0, _generateFunctionMap().generateFunctionMap)(options.projectRoot, ast, {
273      filename
274    });
275    return {
276      code: src,
277      functionMap,
278      ast
279    };
280  }
281
282};
283exports.loaders = loaders;
284//# sourceMappingURL=createMultiRuleTransformer.js.map