1import JsonFile from '@expo/json-file';
2import resolveFrom from 'resolve-from';
3
4import { ExpoConfig } from './Config.types';
5import { ConfigError } from './Errors';
6
7/**
8 * Resolve the Expo SDK Version either from the input Expo config or from the installed
9 * version of the `expo` package.
10 */
11export function getExpoSDKVersion(
12  projectRoot: string,
13  exp: Pick<ExpoConfig, 'sdkVersion'> = {}
14): string {
15  return exp?.sdkVersion ?? getExpoSDKVersionFromPackage(projectRoot);
16}
17
18/**
19 * Resolve the Expo SDK Version either from the input Expo config or from the installed
20 * version of the `expo` package.
21 */
22function getExpoSDKVersionFromPackage(projectRoot: string): string {
23  const packageJsonPath = resolveFrom.silent(projectRoot, 'expo/package.json');
24  if (!packageJsonPath) {
25    throw new ConfigError(
26      `Cannot determine which native SDK version your project uses because the module \`expo\` is not installed. Please install it with \`yarn add expo\` and try again.`,
27      'MODULE_NOT_FOUND'
28    );
29  }
30  const expoPackageJson = JsonFile.read(packageJsonPath, { json5: true });
31  const { version: packageVersion } = expoPackageJson;
32
33  if (!(typeof packageVersion === 'string')) {
34    // This is technically impossible.
35    throw new ConfigError(
36      `Cannot determine which native SDK version your project uses because the module \`expo\` has an invalid package.json (missing \`version\` field). Try reinstalling node modules and trying again.`,
37      'MODULE_NOT_FOUND'
38    );
39  }
40
41  const majorVersion = packageVersion.split('.').shift();
42  return `${majorVersion}.0.0`;
43}
44