1// Copyright 2023-present 650 Industries (Expo). All rights reserved.
2import { getPackageJson } from '@expo/config';
3import { resolveEntryPoint } from '@expo/config/paths';
4import chalk from 'chalk';
5import path from 'path';
6
7import { getServerRoot } from './getModulesPaths';
8
9const debug = require('debug')('expo:metro:config:rewriteRequestUrl');
10
11export function getRewriteRequestUrl(projectRoot: string) {
12  function rewriteExpoRequestUrl(url: string): string {
13    // Like: `/.expo/.virtual-metro-entry.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
14    // Sometimes a fully qualified URL is passed in, e.g. `http://localhost:19001/.expo/.virtual-metro-entry.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
15    if (url.includes('/.expo/.virtual-metro-entry.bundle?')) {
16      const ensured = url.startsWith('/') ? new URL(url, 'https://acme.dev') : new URL(url);
17      // TODO: Maybe this function could be memoized in some capacity?
18      const { search, searchParams } = ensured;
19
20      const platform = searchParams.get('platform') ?? 'web';
21
22      debug('Rewriting magic request url to entry point', { url, platform });
23
24      const entry = resolveEntryPoint(projectRoot, {
25        platform,
26        // @ts-ignore
27        projectConfig: {
28          pkg: getPackageJson(projectRoot),
29        },
30      });
31
32      if (!entry) {
33        throw new Error(
34          chalk`The project entry file could not be resolved (platform: ${platform}, root: ${projectRoot}). Define it in the {bold package.json} "main" field.`
35        );
36      }
37
38      const serverRoot = getServerRoot(projectRoot);
39      const relativeEntry = path.relative(serverRoot, entry).replace(/\.[tj]sx?$/, '');
40      debug('Resolved entry point', { entry, relativeEntry, serverRoot });
41
42      // Like: `/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
43      return '/' + relativeEntry + '.bundle' + search;
44    }
45
46    return url;
47  }
48  return rewriteExpoRequestUrl;
49}
50