1import { ModPlatform, StaticPlugin } from '@expo/config-plugins';
2import { ExpoConfig } from '@expo/config-types';
3
4import { importExpoModulesAutolinking } from './importExpoModulesAutolinking';
5
6/**
7 * Returns a list of packages that are autolinked to a project.
8 *
9 * @param projectRoot
10 * @param platforms platforms to check for
11 * @returns list of packages ex: `['expo-camera', 'react-native-screens']`
12 */
13export async function getAutolinkedPackagesAsync(
14  projectRoot: string,
15  platforms: ModPlatform[] = ['ios', 'android']
16) {
17  const autolinking = importExpoModulesAutolinking(projectRoot);
18  const searchPaths = await autolinking.resolveSearchPathsAsync(null, projectRoot);
19
20  const platformPaths = await Promise.all(
21    platforms.map((platform) =>
22      autolinking.findModulesAsync({
23        platform,
24        searchPaths,
25        silent: true,
26      })
27    )
28  );
29
30  return resolvePackagesList(platformPaths);
31}
32
33export function resolvePackagesList(platformPaths: Record<string, any>[]) {
34  const allPlatformPaths = platformPaths.map((paths) => Object.keys(paths)).flat();
35
36  const uniquePaths = [...new Set(allPlatformPaths)];
37
38  return uniquePaths.sort();
39}
40
41export function shouldSkipAutoPlugin(
42  config: Pick<ExpoConfig, '_internal'>,
43  plugin: StaticPlugin | string
44) {
45  // Hack workaround because expo-dev-client doesn't use expo modules.
46  if (plugin === 'expo-dev-client') {
47    return false;
48  }
49
50  // Only perform the check if `autolinkedModules` is defined, otherwise we assume
51  // this is a legacy runner which doesn't support autolinking.
52  if (Array.isArray(config._internal?.autolinkedModules)) {
53    // Resolve the pluginId as a string.
54    const pluginId = Array.isArray(plugin) ? plugin[0] : plugin;
55    if (typeof pluginId === 'string') {
56      // Determine if the autolinked modules list includes our moduleId
57      const isIncluded = config._internal!.autolinkedModules.includes(pluginId);
58      if (!isIncluded) {
59        // If it doesn't then we know that any potential plugin shouldn't be applied automatically.
60        return true;
61      }
62    }
63  }
64  return false;
65}
66