1import resolveFrom from 'resolve-from';
2
3// These resolvers enable us to test the CLI in older projects.
4// We may be able to get rid of this in the future.
5// TODO: Maybe combine with AsyncResolver?
6class MetroImportError extends Error {
7  constructor(projectRoot: string, moduleId: string) {
8    super(
9      `Missing package "${moduleId}" in the project at: ${projectRoot}\n` +
10        'This usually means "react-native" is not installed. ' +
11        'Please verify that dependencies in package.json include "react-native" ' +
12        'and run `yarn` or `npm install`.'
13    );
14  }
15}
16
17function resolveFromProject(projectRoot: string, moduleId: string) {
18  const resolvedPath = resolveFrom.silent(projectRoot, moduleId);
19  if (!resolvedPath) {
20    throw new MetroImportError(projectRoot, moduleId);
21  }
22  return resolvedPath;
23}
24
25function importFromProject(projectRoot: string, moduleId: string) {
26  return require(resolveFromProject(projectRoot, moduleId));
27}
28
29/** Import `metro` from the project. */
30export function importMetroFromProject(projectRoot: string): typeof import('metro') {
31  return importFromProject(projectRoot, 'metro');
32}
33
34/** Import `@expo/metro-config` from the project. */
35export function importExpoMetroConfigFromProject(
36  projectRoot: string
37): typeof import('@expo/metro-config') {
38  return importFromProject(projectRoot, '@expo/metro-config');
39}
40