1import JsonFile from '@expo/json-file';
2import chalk from 'chalk';
3import resolveFrom from 'resolve-from';
4
5import { getNativeModuleVersionsAsync } from '../../../api/getNativeModuleVersions';
6import { APISettings } from '../../../api/settings';
7import * as Log from '../../../log';
8import { CommandError } from '../../../utils/errors';
9
10const debug = require('debug')(
11  'expo:doctor:dependencies:bundledNativeModules'
12) as typeof console.log;
13
14export type BundledNativeModules = Record<string, string>;
15
16/**
17 * Gets the bundledNativeModules.json for a given SDK version:
18 * - Tries to fetch the data from the /sdks/:sdkVersion/native-modules API endpoint.
19 * - If the data is missing on the server (it can happen for SDKs that are yet fully released)
20 *    or there's a downtime, reads the local .json file from the "expo" package.
21 * - For UNVERSIONED, returns the local .json file contents.
22 */
23export async function getVersionedNativeModulesAsync(
24  projectRoot: string,
25  sdkVersion: string
26): Promise<BundledNativeModules> {
27  if (sdkVersion !== 'UNVERSIONED' && !APISettings.isOffline) {
28    try {
29      debug('Fetching bundled native modules from the server...');
30      return await getNativeModuleVersionsAsync(sdkVersion);
31    } catch {
32      Log.warn(
33        chalk`Unable to reach Expo servers. Falling back to using the cached dependency map ({bold bundledNativeModules.json}) from the package "{bold expo}" installed in your project.`
34      );
35    }
36  }
37
38  debug('Fetching bundled native modules from the local JSON file...');
39  return await getBundledNativeModulesAsync(projectRoot);
40}
41
42/**
43 * Get the legacy static `bundledNativeModules.json` file
44 * that's shipped with the version of `expo` that the project has installed.
45 */
46async function getBundledNativeModulesAsync(projectRoot: string): Promise<BundledNativeModules> {
47  // TODO: Revisit now that this code is in the `expo` package.
48  const bundledNativeModulesPath = resolveFrom.silent(
49    projectRoot,
50    'expo/bundledNativeModules.json'
51  );
52  if (!bundledNativeModulesPath) {
53    Log.log();
54    throw new CommandError(
55      chalk`The dependency map {bold expo/bundledNativeModules.json} cannot be found, please ensure you have the package "{bold expo}" installed in your project.`
56    );
57  }
58  return await JsonFile.readAsync<BundledNativeModules>(bundledNativeModulesPath);
59}
60