1import { createRunOncePlugin, Mod, withDangerousMod } from '@expo/config-plugins';
2import { ExpoConfig } from '@expo/config-types';
3// @ts-expect-error missing types
4import withDevLauncher from 'expo-dev-launcher/app.plugin';
5// @ts-expect-error missing types
6import withDevMenu from 'expo-dev-menu/app.plugin';
7import fs from 'fs';
8import path from 'path';
9
10const pkg = require('expo-dev-client/package.json');
11
12const REACT_NATIVE_CONFIG_JS = `// File created by expo-dev-client/app.plugin.js
13
14module.exports = {
15  dependencies: {
16    ...require('expo-dev-client/dependencies'),
17  },
18};
19`;
20
21function withReactNativeConfigJs(config: ExpoConfig): ExpoConfig {
22  config = withDangerousMod(config, ['android', addReactNativeConfigAsync]);
23  config = withDangerousMod(config, ['ios', addReactNativeConfigAsync]);
24  return config;
25}
26
27const addReactNativeConfigAsync: Mod = async config => {
28  const filename = path.join(config.modRequest.projectRoot, 'react-native.config.js');
29  try {
30    const config = fs.readFileSync(filename, 'utf8');
31    if (!config.includes('expo-dev-client/dependencies')) {
32      throw new Error(
33        `Could not add expo-dev-client dependencies to existing file ${filename}. See expo-dev-client installation instructions to add them manually.`
34      );
35    }
36  } catch (error) {
37    if (error.code === 'ENOENT') {
38      // The file doesn't exist, so we create it.
39      fs.writeFileSync(filename, REACT_NATIVE_CONFIG_JS);
40    } else {
41      throw error;
42    }
43  }
44  return config;
45};
46
47function withDevClient(config: ExpoConfig) {
48  config = withDevMenu(config);
49  config = withDevLauncher(config);
50  config = withReactNativeConfigJs(config);
51  return config;
52}
53
54export default createRunOncePlugin(withDevClient, pkg.name, pkg.version);
55