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