@capacitor/cli 9.0.0-alpha.6 → 9.0.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
Binary file
Binary file
@@ -24,11 +24,14 @@ async function updateAndroid(config) {
24
24
  const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */);
25
25
  (0, plugin_1.printPlugins)(capacitorPlugins, 'android');
26
26
  const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
27
- const enableCordova = cordovaPlugins.length > 0;
27
+ const enableCordova = cordovaPlugins.length > 0 || config.app.forceCordova;
28
28
  await writePluginsJson(config, capacitorPlugins, enableCordova);
29
29
  await removePluginsNativeFiles(config);
30
30
  if (enableCordova) {
31
31
  log_1.logger.info('Found Cordova Plugins: Including Android Cordova Support');
32
+ if (config.app.forceCordova) {
33
+ log_1.logger.info('Cordova support installation has been forced');
34
+ }
32
35
  await copyPluginsNativeFiles(config, cordovaPlugins);
33
36
  }
34
37
  if (!(await (0, fs_extra_1.pathExists)(config.android.webDirAbs))) {
@@ -75,7 +78,7 @@ async function findAndroidPluginClassesInPlugin(plugin) {
75
78
  const srcFiles = await (0, fs_1.readdirp)(srcPath, {
76
79
  filter: (entry) => !entry.stats.isDirectory() && ['.java', '.kt'].includes((0, path_1.extname)(entry.path)),
77
80
  });
78
- const classRegex = /^@(?:CapacitorPlugin|NativePlugin)[\s\S]+?class ([\w]+)/gm;
81
+ const classRegex = /^@CapacitorPlugin[\s\S]+?class ([\w]+)/gm;
79
82
  const packageRegex = /^package ([\w.]+);?$/gm;
80
83
  debug('Searching %O source files in %O by %O regex', srcFiles.length, srcPath, classRegex);
81
84
  const entries = await Promise.all(srcFiles.map(async (srcFile) => {
@@ -107,7 +110,7 @@ async function installGradlePlugins(config, capacitorPlugins, cordovaPlugins) {
107
110
  (0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/android')}.\n` +
108
111
  `Are you sure ${colors_1.default.strong('@capacitor/android')} is installed?`);
109
112
  }
110
- const enableCordova = cordovaPlugins.length > 0;
113
+ const enableCordova = cordovaPlugins.length > 0 || config.app.forceCordova;
111
114
  const capacitorAndroidPath = (0, path_1.resolve)((0, path_1.dirname)(capacitorAndroidPackagePath), 'capacitor');
112
115
  const capacitorCordovaAndroidPath = (0, path_1.resolve)((0, path_1.dirname)(capacitorAndroidPackagePath), 'capacitor-cordova');
113
116
  const settingsPath = config.android.platformDirAbs;
package/dist/common.js CHANGED
@@ -423,7 +423,7 @@ async function checkJDKMajorVersion() {
423
423
  return -1;
424
424
  }
425
425
  }
426
- catch (e) {
426
+ catch {
427
427
  return -1;
428
428
  }
429
429
  }
package/dist/config.js CHANGED
@@ -20,7 +20,7 @@ exports.CONFIG_FILE_NAME_TS = 'capacitor.config.ts';
20
20
  exports.CONFIG_FILE_NAME_JS = 'capacitor.config.js';
21
21
  exports.CONFIG_FILE_NAME_JSON = 'capacitor.config.json';
22
22
  async function loadConfig() {
23
- var _a, _b, _c, _d;
23
+ var _a, _b, _c, _d, _e;
24
24
  const appRootDir = process.cwd();
25
25
  const cliRootDir = (0, path_1.dirname)(__dirname);
26
26
  const conf = await loadExtConfig(appRootDir);
@@ -41,6 +41,7 @@ async function loadConfig() {
41
41
  const appId = (_a = conf.extConfig.appId) !== null && _a !== void 0 ? _a : '';
42
42
  const appName = (_b = conf.extConfig.appName) !== null && _b !== void 0 ? _b : '';
43
43
  const webDir = (_c = conf.extConfig.webDir) !== null && _c !== void 0 ? _c : 'www';
44
+ const forceCordova = (_d = conf.extConfig.forceCordovaInclusion) !== null && _d !== void 0 ? _d : false;
44
45
  const cli = await loadCLIConfig(cliRootDir);
45
46
  const config = {
46
47
  android: await loadAndroidConfig(appRootDir, conf.extConfig, cli),
@@ -53,7 +54,8 @@ async function loadConfig() {
53
54
  appName,
54
55
  webDir,
55
56
  webDirAbs: (0, path_1.resolve)(appRootDir, webDir),
56
- package: (_d = (await (0, fn_1.tryFn)(fs_extra_1.readJSON, (0, path_1.resolve)(appRootDir, 'package.json')))) !== null && _d !== void 0 ? _d : {
57
+ forceCordova,
58
+ package: (_e = (await (0, fn_1.tryFn)(fs_extra_1.readJSON, (0, path_1.resolve)(appRootDir, 'package.json')))) !== null && _e !== void 0 ? _e : {
57
59
  name: appName,
58
60
  version: '1.0.0',
59
61
  ...depsForNx,
@@ -86,8 +88,8 @@ async function loadExtConfigTS(rootDir, extConfigName, extConfigFilePath) {
86
88
  (0, errors_1.fatal)('Could not find installation of TypeScript.\n' +
87
89
  `To use ${colors_1.default.strong(extConfigName)} files, you must install TypeScript in your project, e.g. w/ ${colors_1.default.input('npm install -D typescript')}`);
88
90
  }
89
- const ts = require(tsPath); // eslint-disable-line @typescript-eslint/no-var-requires
90
- const extConfigObject = (0, node_1.requireTS)(ts, extConfigFilePath);
91
+ const ts = require(tsPath); // eslint-disable-line @typescript-eslint/no-require-imports
92
+ const extConfigObject = (await (0, node_1.requireTS)(ts, extConfigFilePath));
91
93
  const extConfig = extConfigObject.default ? await extConfigObject.default : extConfigObject;
92
94
  return {
93
95
  extConfigType: 'ts',
@@ -110,6 +112,7 @@ async function loadExtConfigJS(rootDir, extConfigName, extConfigFilePath) {
110
112
  extConfigType: 'js',
111
113
  extConfigName,
112
114
  extConfigFilePath: extConfigFilePath,
115
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
113
116
  extConfig: await require(extConfigFilePath),
114
117
  };
115
118
  }
@@ -300,7 +303,7 @@ async function determineIOSWebDirAbs(nativeProjectDirAbs, nativeTargetDirAbs, na
300
303
  return (0, path_1.resolve)(nativeProjectDirAbs, 'public');
301
304
  }
302
305
  }
303
- catch (e) {
306
+ catch {
304
307
  // ignore
305
308
  }
306
309
  return (0, path_1.resolve)(nativeTargetDirAbs, 'public');
@@ -384,7 +387,7 @@ async function determinePackageManager(rootDir, platformDir, nativeProjectDirAbs
384
387
  gemfilePath = (0, path_1.resolve)(output, 'Gemfile');
385
388
  }
386
389
  }
387
- catch (e) {
390
+ catch {
388
391
  // Nothing
389
392
  }
390
393
  }
package/dist/cordova.js CHANGED
@@ -754,13 +754,26 @@ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cle
754
754
  });
755
755
  });
756
756
  const cleartextString = 'android:usesCleartextTraffic="true"';
757
- const cleartextValue = (cleartext || ((_a = config.app.extConfig.server) === null || _a === void 0 ? void 0 : _a.cleartext)) && !applicationXMLAttributes.includes(cleartextString)
758
- ? cleartextString
757
+ const networkSecurityConfigValue = cleartext || ((_a = config.app.extConfig.server) === null || _a === void 0 ? void 0 : _a.cleartext) || applicationXMLAttributes.includes(cleartextString)
758
+ ? 'android:networkSecurityConfig="@xml/network_security_config"'
759
759
  : '';
760
+ const networkSecurityConfigDir = (0, path_1.join)(config.android.cordovaPluginsDirAbs, 'src', 'main', 'res', 'xml');
761
+ const networkSecurityConfigPath = (0, path_1.join)(networkSecurityConfigDir, 'network_security_config.xml');
762
+ if (networkSecurityConfigValue) {
763
+ await (0, fs_extra_1.ensureDir)(networkSecurityConfigDir);
764
+ await (0, fs_extra_1.writeFile)(networkSecurityConfigPath, `<?xml version="1.0" encoding="utf-8"?>
765
+ <network-security-config>
766
+ <base-config cleartextTrafficPermitted="true" />
767
+ </network-security-config>
768
+ `);
769
+ }
770
+ else if (await (0, fs_extra_1.pathExists)(networkSecurityConfigPath)) {
771
+ await (0, fs_extra_1.remove)(networkSecurityConfigPath);
772
+ }
760
773
  let content = `<?xml version='1.0' encoding='utf-8'?>
761
774
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
762
775
  xmlns:amazon="http://schemas.amazon.com/apk/res/android">
763
- <application ${applicationXMLAttributes.join('\n')} ${cleartextValue}>
776
+ <application ${applicationXMLAttributes.filter((attr) => !attr.includes('android:usesCleartextTraffic')).join('\n')} ${networkSecurityConfigValue}>
764
777
  ${applicationXMLEntries.join('\n')}
765
778
  </application>
766
779
  ${rootXMLEntries.join('\n')}
@@ -76,6 +76,14 @@ export interface CapacitorConfig {
76
76
  * @default true
77
77
  */
78
78
  initialFocus?: boolean;
79
+ /**
80
+ * If set, will include Cordova support libraries regardless
81
+ * of whether or not they are needed by plugins.
82
+ *
83
+ * @since 9.0.0
84
+ * @default false
85
+ */
86
+ forceCordovaInclusion?: boolean;
79
87
  android?: {
80
88
  /**
81
89
  * Specify a custom path to the native Android project.
@@ -520,6 +528,46 @@ export interface CapacitorConfig {
520
528
  packageOptions?: {
521
529
  [pluginId: string]: PackageOptions;
522
530
  };
531
+ /**
532
+ * Override which Capacitor Swift package the generated `Package.swift` depends on.
533
+ *
534
+ * By default the generated package pins the git tag matching the installed
535
+ * `@capacitor/ios` version, which is correct for both stable and pre-release versions
536
+ * and matches what CocoaPods resolves.
537
+ *
538
+ * Set this only when developing against an unreleased Capacitor, such as a local
539
+ * checkout or a feature branch. Exactly one of `path`, `branch`, `revision`, `exact`,
540
+ * or `from` must be set. `path` points at the repository root (the directory containing
541
+ * `Package.swift`) and may be relative to the app.
542
+ *
543
+ * The `CAPACITOR_IOS_PACKAGE` environment variable takes precedence over this setting,
544
+ * so a checkout can be redirected without editing committed configuration.
545
+ *
546
+ * Note that `branch` and `revision` builds are not reproducible and decouple the native
547
+ * code from the `@capacitor/core` JavaScript bridge it is versioned against.
548
+ *
549
+ * @since 9.0.0
550
+ * @example { "path": "../capacitor" }
551
+ * @example { "branch": "next" }
552
+ */
553
+ capacitorPackage?: {
554
+ /**
555
+ * Repository to fetch from. Ignored when `path` is set.
556
+ *
557
+ * @default 'https://github.com/ionic-team/capacitor'
558
+ */
559
+ url?: string;
560
+ /** Path to a local Capacitor repository root. */
561
+ path?: string;
562
+ /** Branch to track. */
563
+ branch?: string;
564
+ /** Exact commit to pin. */
565
+ revision?: string;
566
+ /** Exact version tag to pin. */
567
+ exact?: string;
568
+ /** Minimum version tag, allowing compatible upgrades. */
569
+ from?: string;
570
+ };
523
571
  };
524
572
  };
525
573
  };
@@ -709,13 +757,31 @@ export interface PluginsConfig {
709
757
  *
710
758
  * This option is only supported on Android.
711
759
  *
712
- * `css` = Injects CSS variables (`--safe-area-inset-*`) containing correct safe area inset values into the webview.
760
+ * `native` = (recommended) For older Chromium versions (< v140) this embeds the webview with padding and sets the `env(safe-area-inset-*)` variables to `0px`. For newer Chromium versions (>= v140) this makes sure the webview adheres to the `viewport-fit` meta tag. If set to `viewport-fit="cover"` this will make the webview edge-to-edge and the `env(safe-area-inset-*)` variables will contain the correct values. With those values you could set padding for example so make sure the webview is shown correctly.
761
+ *
762
+ * `css` = This is the same as `native`, but it also injects CSS variables (`--safe-area-inset-*`) containing correct safe area inset values into the webview.
763
+ *
764
+ * `disable` = (not recommended) Disable safe area insets handling completely.
765
+ * This shifts the responsibility from Capacitor to your own code to handle the insets.
766
+ * Be aware that this might result in a visually broken UI if your native app code and the content loaded into the webview do not correctly handle safe area insets.
713
767
  *
714
- * `disable` = Disable CSS variables injection.
768
+ * @default "native"
769
+ */
770
+ insetsHandling?: 'native' | 'css' | 'disable';
771
+ /**
772
+ * Set an initial value for the to be detected `viewport-fit=` meta tag value.
773
+ * For most apps that support edge-to-edge this value will eventually be `cover`.
774
+ * Therefore you might want to set this value to `cover` to help prevent layout jumps and glitches.
775
+ * If you know the value to be `cover` initially, you can set it here.
776
+ * The value will always end up correctly, no matter what you set here,
777
+ * as long as `insetsHandling` is set to `native` or `css`.
778
+ * It only exists to help prevent layout jumps and glitches.
779
+ *
780
+ * This option is only supported on Android.
715
781
  *
716
- * @default "css"
782
+ * @default undefined
717
783
  */
718
- insetsHandling?: 'css' | 'disable';
784
+ initialViewportFitValueHint?: 'auto' | 'contain' | 'cover';
719
785
  /**
720
786
  * The style of the text and icons of the system bars.
721
787
  *
@@ -21,7 +21,7 @@ function execBundler() {
21
21
  const bundleOutput = (0, child_process_1.execSync)('bundle &> /dev/null ; echo $?');
22
22
  return parseInt(bundleOutput.toString());
23
23
  }
24
- catch (e) {
24
+ catch {
25
25
  return -1;
26
26
  }
27
27
  }
@@ -13,6 +13,7 @@ const log_1 = require("../log");
13
13
  const plugin_1 = require("../plugin");
14
14
  const copy_1 = require("../tasks/copy");
15
15
  const migrate_1 = require("../tasks/migrate");
16
+ const capacitor_package_1 = require("../util/capacitor-package");
16
17
  const cordova_ios_1 = require("../util/cordova-ios");
17
18
  const fs_1 = require("../util/fs");
18
19
  const iosplugin_1 = require("../util/iosplugin");
@@ -34,9 +35,12 @@ async function updatePluginFiles(config, plugins, deployment) {
34
35
  var _a;
35
36
  await (0, cordova_ios_1.removePluginsNativeFiles)(config);
36
37
  const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
37
- const enableCordova = cordovaPlugins.length > 0;
38
+ const enableCordova = cordovaPlugins.length > 0 || config.app.forceCordova;
38
39
  if (enableCordova) {
39
40
  log_1.logger.info('Found Cordova Plugins: Including iOS Cordova Support');
41
+ if (config.app.forceCordova) {
42
+ log_1.logger.info('Cordova support installation has been forced');
43
+ }
40
44
  await (0, cordova_ios_1.copyPluginsNativeFiles)(config, cordovaPlugins);
41
45
  }
42
46
  if (!(await (0, fs_extra_1.pathExists)(await config.ios.webDirAbs))) {
@@ -49,20 +53,32 @@ async function updatePluginFiles(config, plugins, deployment) {
49
53
  await (0, cordova_ios_1.generateCordovaPackageFiles)(cordovaPlugins, config);
50
54
  }
51
55
  const validSPMPackages = await (0, spm_1.checkPluginsForPackageSwift)(config, plugins);
56
+ const iosPlatformVersion = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name);
57
+ const majorCapVersion = (0, semver_1.major)(iosPlatformVersion);
58
+ const capacitorPackage = await (0, capacitor_package_1.resolveCapacitorPackage)(config, 'from');
59
+ const iosVersion = (0, common_2.getMajoriOSVersion)(config);
52
60
  await Promise.all(validSPMPackages.map(async (plugin) => {
53
- var _a;
54
- const iosPlatformVersion = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name);
55
61
  const packageSwiftPath = (0, path_1.join)(plugin.rootPath, 'Package.swift');
56
62
  let content = await (0, fs_extra_1.readFile)(packageSwiftPath, { encoding: 'utf-8' });
57
- const regex = new RegExp('url:\\s*"https://github.com/ionic-team/capacitor-swift-pm\\.git",\\s*from:\\s*"([^"]+)"');
58
- const version = (_a = content.match(regex)) === null || _a === void 0 ? void 0 : _a[1];
59
- const majorCapVersion = (0, semver_1.major)(iosPlatformVersion);
63
+ const version = (0, capacitor_package_1.findCapacitorDependencyVersion)(content);
64
+ if (version && (0, semver_1.major)(version) != majorCapVersion) {
65
+ log_1.logger.warn(`${plugin.id} is built for Capacitor ${(0, semver_1.major)(version)}, it might cause issues`);
66
+ }
67
+ if (capacitorPackage.sourceBased) {
68
+ // The plugin has to resolve to the same package identity as the app, or SPM ends up with
69
+ // two packages that both vend a Capacitor product.
70
+ let rewritten = (0, capacitor_package_1.rewriteCapacitorDependency)(content, capacitorPackage, plugin.rootPath);
71
+ rewritten = (0, capacitor_package_1.patchPackageSwiftDeploymentTarget)(rewritten, iosVersion).content;
72
+ if (rewritten !== content) {
73
+ await (0, fs_extra_1.writeFile)(packageSwiftPath, rewritten);
74
+ }
75
+ return;
76
+ }
60
77
  if (version && (0, semver_1.major)(version) != majorCapVersion) {
61
78
  const preCapVersion = (0, semver_1.prerelease)(iosPlatformVersion);
62
79
  const forceVersion = preCapVersion ? iosPlatformVersion : `${majorCapVersion}.0.0`;
63
80
  content = (0, migrate_1.setAllStringIn)(content, `url: "https://github.com/ionic-team/capacitor-swift-pm.git",`, `)`, ` from: "${forceVersion}"`);
64
81
  await (0, fs_extra_1.writeFile)(packageSwiftPath, content);
65
- log_1.logger.warn(`${plugin.id} is built for Capacitor ${(0, semver_1.major)(version)}, it might cause issues`);
66
82
  }
67
83
  }));
68
84
  await (0, spm_1.generatePackageFile)(config, validSPMPackages.concat(cordovaPlugins));
package/dist/plugin.js CHANGED
@@ -59,7 +59,7 @@ async function resolvePlugin(config, name) {
59
59
  xml: xmlMeta.plugin,
60
60
  };
61
61
  }
62
- catch (e) {
62
+ catch {
63
63
  // ignore
64
64
  }
65
65
  return null;
@@ -26,7 +26,7 @@ async function listCommand(config, selectedPlatformName) {
26
26
  exports.listCommand = listCommand;
27
27
  async function list(config, platform) {
28
28
  const allPlugins = await (0, plugin_1.getPlugins)(config, platform);
29
- let plugins = [];
29
+ let plugins;
30
30
  if (platform === config.ios.name) {
31
31
  plugins = await (0, common_3.getIOSPlugins)(allPlugins);
32
32
  }
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.__testables = exports.migrateToEdgeToEdge = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const path_1 = require("path");
6
+ const log_1 = require("../log");
7
+ const fs_1 = require("../util/fs");
8
+ const JAVA = {
9
+ imports: ['import android.os.Bundle;', 'import androidx.activity.EdgeToEdge;'],
10
+ enableCall: 'EdgeToEdge.enable(this);',
11
+ onCreate: `
12
+ @Override
13
+ protected void onCreate(Bundle savedInstanceState) {
14
+ super.onCreate(savedInstanceState);
15
+ EdgeToEdge.enable(this);
16
+ }
17
+ `,
18
+ };
19
+ const KOTLIN = {
20
+ imports: ['import android.os.Bundle', 'import androidx.activity.enableEdgeToEdge'],
21
+ enableCall: 'enableEdgeToEdge()',
22
+ onCreate: `
23
+ override fun onCreate(savedInstanceState: Bundle?) {
24
+ super.onCreate(savedInstanceState)
25
+ enableEdgeToEdge()
26
+ }
27
+ `,
28
+ };
29
+ async function migrateToEdgeToEdge(config) {
30
+ var _a, _b;
31
+ if (((_b = (_a = config.app.extConfig.plugins) === null || _a === void 0 ? void 0 : _a.SystemBars) === null || _b === void 0 ? void 0 : _b.insetsHandling) === 'disable') {
32
+ log_1.logger.info(`Edge-to-edge migration: SystemBars insetsHandling is 'disable', skipping.`);
33
+ return;
34
+ }
35
+ const activities = await findBridgeActivities(config);
36
+ if (activities.length === 0) {
37
+ log_1.logger.warn(`Edge-to-edge migration: no Activity extending BridgeActivity found. ${manualInstructions(JAVA.enableCall)}`);
38
+ return;
39
+ }
40
+ if (activities.length > 1) {
41
+ log_1.logger.warn(`Edge-to-edge migration: found more than one Activity extending BridgeActivity (${activities.join(', ')}), ` +
42
+ `skipping. ${manualInstructions(JAVA.enableCall)}`);
43
+ return;
44
+ }
45
+ const path = activities[0];
46
+ const language = path.endsWith('.kt') ? KOTLIN : JAVA;
47
+ const source = (0, fs_extra_1.readFileSync)(path, 'utf-8');
48
+ if (hasEdgeToEdgeEnabled(source)) {
49
+ log_1.logger.info('Edge-to-edge migration: Activity already enables edge-to-edge, skipping.');
50
+ return;
51
+ }
52
+ const patched = patchActivitySource(source, language);
53
+ if (!patched) {
54
+ log_1.logger.warn(`Edge-to-edge migration: could not patch ${path}. ${manualInstructions(language.enableCall)}`);
55
+ return;
56
+ }
57
+ (0, fs_extra_1.writeFileSync)(path, patched, 'utf-8');
58
+ }
59
+ exports.migrateToEdgeToEdge = migrateToEdgeToEdge;
60
+ function manualInstructions(enableCall) {
61
+ return (`Add ${enableCall} to the onCreate of the Activity hosting Capacitor. ` +
62
+ `Without it the 'native' insetsHandling default of the SystemBars plugin cannot apply safe area insets.`);
63
+ }
64
+ async function findBridgeActivities(config) {
65
+ const javaDir = (0, path_1.join)(config.android.srcMainDirAbs, 'java');
66
+ if (!(0, fs_extra_1.existsSync)(javaDir)) {
67
+ return [];
68
+ }
69
+ const sources = await (0, fs_1.readdirp)(javaDir, {
70
+ filter: (entry) => !entry.stats.isDirectory() && (entry.path.endsWith('.java') || entry.path.endsWith('.kt')),
71
+ });
72
+ return sources.filter((path) => (0, fs_extra_1.readFileSync)(path, 'utf-8').includes('BridgeActivity'));
73
+ }
74
+ function hasEdgeToEdgeEnabled(source) {
75
+ return source.includes('EdgeToEdge.enable(') || source.includes('enableEdgeToEdge(');
76
+ }
77
+ function patchActivitySource(source, language) {
78
+ var _a;
79
+ const patched = (_a = insertEnableCall(source, language)) !== null && _a !== void 0 ? _a : insertOnCreate(source, language);
80
+ if (!patched) {
81
+ return undefined;
82
+ }
83
+ return addImports(patched, language.imports);
84
+ }
85
+ function insertEnableCall(source, language) {
86
+ var _a, _b;
87
+ const lines = source.split('\n');
88
+ const superCall = lines.findIndex((line) => line.includes('super.onCreate('));
89
+ if (superCall === -1) {
90
+ return undefined;
91
+ }
92
+ const indentation = (_b = (_a = lines[superCall].match(/^\s*/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : '';
93
+ lines.splice(superCall + 1, 0, `${indentation}${language.enableCall}`);
94
+ return lines.join('\n');
95
+ }
96
+ function insertOnCreate(source, language) {
97
+ const classDeclaration = source.search(/\bclass\s+\w+/);
98
+ if (classDeclaration === -1) {
99
+ return undefined;
100
+ }
101
+ const bodyStart = source.indexOf('{', classDeclaration);
102
+ if (bodyStart === -1) {
103
+ return undefined;
104
+ }
105
+ const bodyEnd = findMatchingBrace(source, bodyStart);
106
+ if (bodyEnd === -1) {
107
+ return undefined;
108
+ }
109
+ const body = source.slice(0, bodyEnd).replace(/\s*$/, '\n');
110
+ return body + language.onCreate + source.slice(bodyEnd);
111
+ }
112
+ function findMatchingBrace(source, openIndex) {
113
+ let depth = 0;
114
+ for (let i = openIndex; i < source.length; i++) {
115
+ if (source[i] === '{') {
116
+ depth++;
117
+ }
118
+ else if (source[i] === '}') {
119
+ depth--;
120
+ if (depth === 0) {
121
+ return i;
122
+ }
123
+ }
124
+ }
125
+ return -1;
126
+ }
127
+ function addImports(source, statements) {
128
+ const lines = source.split('\n');
129
+ for (const statement of statements) {
130
+ if (!lines.includes(statement)) {
131
+ lines.splice(importInsertIndex(lines, statement), 0, statement);
132
+ }
133
+ }
134
+ return lines.join('\n');
135
+ }
136
+ function importInsertIndex(lines, statement) {
137
+ const sortsAfter = lines.findIndex((line) => line.startsWith('import ') && line > statement);
138
+ if (sortsAfter !== -1) {
139
+ return sortsAfter;
140
+ }
141
+ let lastImport = -1;
142
+ lines.forEach((line, index) => {
143
+ if (line.startsWith('import ')) {
144
+ lastImport = index;
145
+ }
146
+ });
147
+ if (lastImport !== -1) {
148
+ return lastImport + 1;
149
+ }
150
+ return lines.findIndex((line) => line.startsWith('package ')) + 1;
151
+ }
152
+ exports.__testables = {
153
+ JAVA,
154
+ KOTLIN,
155
+ addImports,
156
+ hasEdgeToEdgeEnabled,
157
+ patchActivitySource,
158
+ };