1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3    return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const config_plugins_1 = require("@expo/config-plugins");
7const fs_1 = __importDefault(require("fs"));
8const path_1 = __importDefault(require("path"));
9const semver_1 = __importDefault(require("semver"));
10const resolveExpoUpdatesVersion_1 = require("./resolveExpoUpdatesVersion");
11const withDevLauncherAppDelegate_1 = require("./withDevLauncherAppDelegate");
12const pkg = require('expo-dev-launcher/package.json');
13const DEV_LAUNCHER_ANDROID_IMPORT = 'expo.modules.devlauncher.DevLauncherController';
14const DEV_LAUNCHER_UPDATES_ANDROID_IMPORT = 'expo.modules.updates.UpdatesDevLauncherController';
15const DEV_LAUNCHER_ON_NEW_INTENT = `
16  @Override
17  public void onNewIntent(Intent intent) {
18      if (DevLauncherController.tryToHandleIntent(this, intent)) {
19         return;
20      }
21      super.onNewIntent(intent);
22  }
23`;
24const DEV_LAUNCHER_WRAPPED_ACTIVITY_DELEGATE = `DevLauncherController.wrapReactActivityDelegate(this, () -> $1);`;
25const DEV_LAUNCHER_ANDROID_INIT = 'DevLauncherController.initialize(this, getReactNativeHost());';
26const DEV_LAUNCHER_UPDATES_ANDROID_INIT = `if (BuildConfig.DEBUG) {
27      DevLauncherController.getInstance().setUpdatesInterface(UpdatesDevLauncherController.initialize(this));
28    }`;
29const DEV_LAUNCHER_UPDATES_DEVELOPER_SUPPORT = 'return DevLauncherController.getInstance().getUseDeveloperSupport();';
30const DEV_LAUNCHER_JS_REGISTER_ERROR_HANDLERS = `import 'expo-dev-client';`;
31async function readFileAsync(path) {
32    return fs_1.default.promises.readFile(path, 'utf8');
33}
34async function saveFileAsync(path, content) {
35    return fs_1.default.promises.writeFile(path, content, 'utf8');
36}
37function addLines(content, find, offset, toAdd) {
38    const lines = content.split('\n');
39    let lineIndex = lines.findIndex(line => line.match(find));
40    for (const newLine of toAdd) {
41        if (!content.includes(newLine)) {
42            lines.splice(lineIndex + offset, 0, newLine);
43            lineIndex++;
44        }
45    }
46    return lines.join('\n');
47}
48function replaceLine(content, find, replace) {
49    const lines = content.split('\n');
50    if (!content.includes(replace)) {
51        const lineIndex = lines.findIndex(line => line.match(find));
52        lines.splice(lineIndex, 1, replace);
53    }
54    return lines.join('\n');
55}
56function addJavaImports(javaSource, javaImports) {
57    const lines = javaSource.split('\n');
58    const lineIndexWithPackageDeclaration = lines.findIndex(line => line.match(/^package .*;$/));
59    for (const javaImport of javaImports) {
60        if (!javaSource.includes(javaImport)) {
61            const importStatement = `import ${javaImport};`;
62            lines.splice(lineIndexWithPackageDeclaration + 1, 0, importStatement);
63        }
64    }
65    return lines.join('\n');
66}
67async function editMainApplication(config, action) {
68    const mainApplicationPath = path_1.default.join(config.modRequest.platformProjectRoot, 'app', 'src', 'main', 'java', ...config.android.package.split('.'), 'MainApplication.java');
69    try {
70        const mainApplication = action(await readFileAsync(mainApplicationPath));
71        return await saveFileAsync(mainApplicationPath, mainApplication);
72    }
73    catch (e) {
74        config_plugins_1.WarningAggregator.addWarningIOS('expo-dev-launcher', `Couldn't modify MainApplication.java - ${e}.`);
75    }
76}
77async function editPodfile(config, action) {
78    const podfilePath = path_1.default.join(config.modRequest.platformProjectRoot, 'Podfile');
79    try {
80        const podfile = action(await readFileAsync(podfilePath));
81        return await saveFileAsync(podfilePath, podfile);
82    }
83    catch (e) {
84        config_plugins_1.WarningAggregator.addWarningIOS('expo-dev-launcher', `Couldn't modify AppDelegate.m - ${e}.`);
85    }
86}
87async function editIndex(config, action) {
88    const indexPath = path_1.default.join(config.modRequest.projectRoot, 'index.js');
89    try {
90        const index = action(await readFileAsync(indexPath));
91        return await saveFileAsync(indexPath, index);
92    }
93    catch (e) {
94        config_plugins_1.WarningAggregator.addWarningIOS('expo-dev-launcher', `Couldn't modify index.js - ${e}.`);
95    }
96}
97const withDevLauncherApplication = config => {
98    return config_plugins_1.withDangerousMod(config, [
99        'android',
100        async (config) => {
101            await editMainApplication(config, mainApplication => {
102                mainApplication = addJavaImports(mainApplication, [DEV_LAUNCHER_ANDROID_IMPORT]);
103                mainApplication = addLines(mainApplication, 'initializeFlipper\\(this', 0, [
104                    `    ${DEV_LAUNCHER_ANDROID_INIT}`,
105                ]);
106                let expoUpdatesVersion;
107                try {
108                    expoUpdatesVersion = resolveExpoUpdatesVersion_1.resolveExpoUpdatesVersion(config.modRequest.projectRoot);
109                }
110                catch (e) {
111                    config_plugins_1.WarningAggregator.addWarningAndroid('expo-dev-launcher', `Failed to check compatibility with expo-updates - ${e}`);
112                }
113                if (expoUpdatesVersion && semver_1.default.gt(expoUpdatesVersion, '0.6.0')) {
114                    mainApplication = addJavaImports(mainApplication, [DEV_LAUNCHER_UPDATES_ANDROID_IMPORT]);
115                    mainApplication = addLines(mainApplication, 'initializeFlipper\\(this', 0, [
116                        `    ${DEV_LAUNCHER_UPDATES_ANDROID_INIT}`,
117                    ]);
118                    mainApplication = replaceLine(mainApplication, 'return BuildConfig.DEBUG;', `      ${DEV_LAUNCHER_UPDATES_DEVELOPER_SUPPORT}`);
119                }
120                return mainApplication;
121            });
122            return config;
123        },
124    ]);
125};
126const withDevLauncherActivity = config => {
127    return config_plugins_1.withMainActivity(config, config => {
128        if (config.modResults.language === 'java') {
129            let content = addJavaImports(config.modResults.contents, [
130                DEV_LAUNCHER_ANDROID_IMPORT,
131                'android.content.Intent',
132            ]);
133            if (!content.includes(DEV_LAUNCHER_ON_NEW_INTENT)) {
134                const lines = content.split('\n');
135                const onCreateIndex = lines.findIndex(line => line.includes('public class MainActivity'));
136                lines.splice(onCreateIndex + 1, 0, DEV_LAUNCHER_ON_NEW_INTENT);
137                content = lines.join('\n');
138            }
139            if (!content.includes('DevLauncherController.wrapReactActivityDelegate')) {
140                content = content.replace(/(new ReactActivityDelegate(.*|\s)*});$/m, DEV_LAUNCHER_WRAPPED_ACTIVITY_DELEGATE);
141            }
142            config.modResults.contents = content;
143        }
144        else {
145            config_plugins_1.WarningAggregator.addWarningAndroid('expo-dev-launcher', `Cannot automatically configure MainActivity if it's not java`);
146        }
147        return config;
148    });
149};
150const withDevLauncherPodfile = config => {
151    return config_plugins_1.withDangerousMod(config, [
152        'ios',
153        async (config) => {
154            await editPodfile(config, podfile => {
155                podfile = podfile.replace("platform :ios, '10.0'", "platform :ios, '11.0'");
156                // Match both variations of Ruby config:
157                // unknown: pod 'expo-dev-launcher', path: '../node_modules/expo-dev-launcher', :configurations => :debug
158                // Rubocop: pod 'expo-dev-launcher', path: '../node_modules/expo-dev-launcher', configurations: :debug
159                if (!podfile.match(/pod ['"]expo-dev-launcher['"],\s?path: ['"][^'"]*node_modules\/expo-dev-launcher['"],\s?:?configurations:?\s(?:=>\s)?:debug/)) {
160                    const packagePath = path_1.default.dirname(require.resolve('expo-dev-launcher/package.json'));
161                    const relativePath = path_1.default.relative(config.modRequest.platformProjectRoot, packagePath);
162                    podfile = addLines(podfile, 'use_react_native', 0, [
163                        `  pod 'expo-dev-launcher', path: '${relativePath}', :configurations => :debug`,
164                    ]);
165                }
166                return podfile;
167            });
168            return config;
169        },
170    ]);
171};
172const withErrorHandling = config => {
173    const injectErrorHandlers = async (config) => {
174        await editIndex(config, index => {
175            if (!index.includes(DEV_LAUNCHER_JS_REGISTER_ERROR_HANDLERS)) {
176                index = DEV_LAUNCHER_JS_REGISTER_ERROR_HANDLERS + '\n\n' + index;
177            }
178            return index;
179        });
180        return config;
181    };
182    // We need to run the same task twice to ensure it will work on both platforms,
183    // because if someone runs `expo run:ios`, it will trigger only dangerous mode for that specific platform.
184    // Note: after the first execution, the second one won't change anything.
185    config = config_plugins_1.withDangerousMod(config, ['android', injectErrorHandlers]);
186    config = config_plugins_1.withDangerousMod(config, ['ios', injectErrorHandlers]);
187    return config;
188};
189const withDevLauncher = (config) => {
190    config = withDevLauncherActivity(config);
191    config = withDevLauncherApplication(config);
192    config = withDevLauncherPodfile(config);
193    config = withDevLauncherAppDelegate_1.withDevLauncherAppDelegate(config);
194    config = withErrorHandling(config);
195    return config;
196};
197exports.default = config_plugins_1.createRunOncePlugin(withDevLauncher, pkg.name, pkg.version);
198