1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4  value: true
5});
6exports.getApplicationIdAsync = getApplicationIdAsync;
7exports.getPackage = getPackage;
8exports.renameJniOnDiskForType = renameJniOnDiskForType;
9exports.renamePackageOnDisk = renamePackageOnDisk;
10exports.renamePackageOnDiskForType = renamePackageOnDiskForType;
11exports.setPackageInAndroidManifest = setPackageInAndroidManifest;
12exports.setPackageInBuildGradle = setPackageInBuildGradle;
13exports.withPackageRefactor = exports.withPackageManifest = exports.withPackageGradle = void 0;
14function _debug() {
15  const data = _interopRequireDefault(require("debug"));
16  _debug = function () {
17    return data;
18  };
19  return data;
20}
21function _fs() {
22  const data = _interopRequireDefault(require("fs"));
23  _fs = function () {
24    return data;
25  };
26  return data;
27}
28function _glob() {
29  const data = require("glob");
30  _glob = function () {
31    return data;
32  };
33  return data;
34}
35function _path() {
36  const data = _interopRequireDefault(require("path"));
37  _path = function () {
38    return data;
39  };
40  return data;
41}
42function _androidPlugins() {
43  const data = require("../plugins/android-plugins");
44  _androidPlugins = function () {
45    return data;
46  };
47  return data;
48}
49function _withDangerousMod() {
50  const data = require("../plugins/withDangerousMod");
51  _withDangerousMod = function () {
52    return data;
53  };
54  return data;
55}
56function _modules() {
57  const data = require("../utils/modules");
58  _modules = function () {
59    return data;
60  };
61  return data;
62}
63function _warnings() {
64  const data = require("../utils/warnings");
65  _warnings = function () {
66    return data;
67  };
68  return data;
69}
70function _Paths() {
71  const data = require("./Paths");
72  _Paths = function () {
73    return data;
74  };
75  return data;
76}
77function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
78const debug = (0, _debug().default)('expo:config-plugins:android:package');
79const withPackageManifest = (0, _androidPlugins().createAndroidManifestPlugin)(setPackageInAndroidManifest, 'withPackageManifest');
80exports.withPackageManifest = withPackageManifest;
81const withPackageGradle = config => {
82  return (0, _androidPlugins().withAppBuildGradle)(config, config => {
83    if (config.modResults.language === 'groovy') {
84      config.modResults.contents = setPackageInBuildGradle(config, config.modResults.contents);
85    } else {
86      (0, _warnings().addWarningAndroid)('android.package', `Cannot automatically configure app build.gradle if it's not groovy`);
87    }
88    return config;
89  });
90};
91exports.withPackageGradle = withPackageGradle;
92const withPackageRefactor = config => {
93  return (0, _withDangerousMod().withDangerousMod)(config, ['android', async config => {
94    await renamePackageOnDisk(config, config.modRequest.projectRoot);
95    return config;
96  }]);
97};
98exports.withPackageRefactor = withPackageRefactor;
99function getPackage(config) {
100  var _config$android$packa, _config$android;
101  return (_config$android$packa = (_config$android = config.android) === null || _config$android === void 0 ? void 0 : _config$android.package) !== null && _config$android$packa !== void 0 ? _config$android$packa : null;
102}
103function getPackageRoot(projectRoot, type) {
104  return _path().default.join(projectRoot, 'android', 'app', 'src', type, 'java');
105}
106function getCurrentPackageName(projectRoot, packageRoot) {
107  const mainApplication = (0, _Paths().getProjectFilePath)(projectRoot, 'MainApplication');
108  const packagePath = _path().default.dirname(mainApplication);
109  const packagePathParts = _path().default.relative(packageRoot, packagePath).split(_path().default.sep).filter(Boolean);
110  return packagePathParts.join('.');
111}
112function getCurrentPackageForProjectFile(projectRoot, packageRoot, fileName, type) {
113  const filePath = (0, _glob().sync)(_path().default.join(projectRoot, `android/app/src/${type}/java/**/${fileName}.@(java|kt)`))[0];
114  if (!filePath) {
115    return null;
116  }
117  const packagePath = _path().default.dirname(filePath);
118  const packagePathParts = _path().default.relative(packageRoot, packagePath).split(_path().default.sep).filter(Boolean);
119  return packagePathParts.join('.');
120}
121function getCurrentPackageNameForType(projectRoot, type) {
122  const packageRoot = getPackageRoot(projectRoot, type);
123  if (type === 'main') {
124    return getCurrentPackageName(projectRoot, packageRoot);
125  }
126  // debug, etc..
127  return getCurrentPackageForProjectFile(projectRoot, packageRoot, '*', type);
128}
129
130// NOTE(brentvatne): this assumes that our MainApplication.java file is in the root of the package
131// this makes sense for standard react-native projects but may not apply in customized projects, so if
132// we want this to be runnable in any app we need to handle other possibilities
133async function renamePackageOnDisk(config, projectRoot) {
134  const newPackageName = getPackage(config);
135  if (newPackageName === null) {
136    return;
137  }
138  for (const type of ['debug', 'main', 'release']) {
139    await renameJniOnDiskForType({
140      projectRoot,
141      type,
142      packageName: newPackageName
143    });
144    await renamePackageOnDiskForType({
145      projectRoot,
146      type,
147      packageName: newPackageName
148    });
149  }
150}
151async function renameJniOnDiskForType({
152  projectRoot,
153  type,
154  packageName
155}) {
156  if (!packageName) {
157    return;
158  }
159  const currentPackageName = getCurrentPackageNameForType(projectRoot, type);
160  if (!currentPackageName || !packageName || currentPackageName === packageName) {
161    return;
162  }
163  const jniRoot = _path().default.join(projectRoot, 'android', 'app', 'src', type, 'jni');
164  const filesToUpdate = [...(0, _glob().sync)('**/*', {
165    cwd: jniRoot,
166    absolute: true
167  })];
168  // Replace all occurrences of the path in the project
169  filesToUpdate.forEach(filepath => {
170    try {
171      if (_fs().default.lstatSync(filepath).isFile() && ['.h', '.cpp'].includes(_path().default.extname(filepath))) {
172        let contents = _fs().default.readFileSync(filepath).toString();
173        contents = contents.replace(new RegExp(transformJavaClassDescriptor(currentPackageName).replace(/\//g, '\\/'), 'g'), transformJavaClassDescriptor(packageName));
174        _fs().default.writeFileSync(filepath, contents);
175      }
176    } catch {
177      debug(`Error updating "${filepath}" for type "${type}"`);
178    }
179  });
180}
181async function renamePackageOnDiskForType({
182  projectRoot,
183  type,
184  packageName
185}) {
186  if (!packageName) {
187    return;
188  }
189  const currentPackageName = getCurrentPackageNameForType(projectRoot, type);
190  debug(`Found package "${currentPackageName}" for type "${type}"`);
191  if (!currentPackageName || currentPackageName === packageName) {
192    return;
193  }
194  debug(`Refactor "${currentPackageName}" to "${packageName}" for type "${type}"`);
195  const packageRoot = getPackageRoot(projectRoot, type);
196  // Set up our paths
197  if (!(await (0, _modules().directoryExistsAsync)(packageRoot))) {
198    debug(`- skipping refactor of missing directory: ${packageRoot}`);
199    return;
200  }
201  const currentPackagePath = _path().default.join(packageRoot, ...currentPackageName.split('.'));
202  const newPackagePath = _path().default.join(packageRoot, ...packageName.split('.'));
203
204  // Create the new directory
205  _fs().default.mkdirSync(newPackagePath, {
206    recursive: true
207  });
208
209  // Move everything from the old directory over
210  (0, _glob().sync)('**/*', {
211    cwd: currentPackagePath
212  }).forEach(relativePath => {
213    const filepath = _path().default.join(currentPackagePath, relativePath);
214    if (_fs().default.lstatSync(filepath).isFile()) {
215      moveFileSync(filepath, _path().default.join(newPackagePath, relativePath));
216    } else {
217      _fs().default.mkdirSync(filepath, {
218        recursive: true
219      });
220    }
221  });
222
223  // Remove the old directory recursively from com/old/package to com/old and com,
224  // as long as the directories are empty
225  const oldPathParts = currentPackageName.split('.');
226  while (oldPathParts.length) {
227    const pathToCheck = _path().default.join(packageRoot, ...oldPathParts);
228    try {
229      const files = _fs().default.readdirSync(pathToCheck);
230      if (files.length === 0) {
231        _fs().default.rmdirSync(pathToCheck);
232      }
233    } finally {
234      oldPathParts.pop();
235    }
236  }
237  const filesToUpdate = [...(0, _glob().sync)('**/*', {
238    cwd: newPackagePath,
239    absolute: true
240  })];
241  // Only update the BUCK file to match the main package name
242  if (type === 'main') {
243    // NOTE(EvanBacon): We dropped this file in SDK 48 but other templates may still use it.
244    filesToUpdate.push(_path().default.join(projectRoot, 'android', 'app', 'BUCK'));
245  }
246  // Replace all occurrences of the path in the project
247  filesToUpdate.forEach(filepath => {
248    try {
249      if (_fs().default.lstatSync(filepath).isFile()) {
250        let contents = _fs().default.readFileSync(filepath).toString();
251        contents = contents.replace(new RegExp(currentPackageName, 'g'), packageName);
252        if (['.h', '.cpp'].includes(_path().default.extname(filepath))) {
253          contents = contents.replace(new RegExp(transformJavaClassDescriptor(currentPackageName).replace(/\//g, '\\'), 'g'), transformJavaClassDescriptor(packageName));
254        }
255        _fs().default.writeFileSync(filepath, contents);
256      }
257    } catch {
258      debug(`Error updating "${filepath}" for type "${type}"`);
259    }
260  });
261}
262function moveFileSync(src, dest) {
263  _fs().default.mkdirSync(_path().default.dirname(dest), {
264    recursive: true
265  });
266  _fs().default.renameSync(src, dest);
267}
268function setPackageInBuildGradle(config, buildGradle) {
269  const packageName = getPackage(config);
270  if (packageName === null) {
271    return buildGradle;
272  }
273  const pattern = new RegExp(`(applicationId|namespace) ['"].*['"]`, 'g');
274  return buildGradle.replace(pattern, `$1 '${packageName}'`);
275}
276function setPackageInAndroidManifest(config, androidManifest) {
277  const packageName = getPackage(config);
278  if (packageName) {
279    androidManifest.manifest.$.package = packageName;
280  } else {
281    delete androidManifest.manifest.$.package;
282  }
283  return androidManifest;
284}
285async function getApplicationIdAsync(projectRoot) {
286  var _matchResult$;
287  const buildGradlePath = (0, _Paths().getAppBuildGradleFilePath)(projectRoot);
288  if (!_fs().default.existsSync(buildGradlePath)) {
289    return null;
290  }
291  const buildGradle = await _fs().default.promises.readFile(buildGradlePath, 'utf8');
292  const matchResult = buildGradle.match(/applicationId ['"](.*)['"]/);
293  // TODO add fallback for legacy cases to read from AndroidManifest.xml
294  return (_matchResult$ = matchResult === null || matchResult === void 0 ? void 0 : matchResult[1]) !== null && _matchResult$ !== void 0 ? _matchResult$ : null;
295}
296
297/**
298 * Transform a java package name to java class descriptor,
299 * e.g. `com.helloworld` -> `Lcom/helloworld`.
300 */
301function transformJavaClassDescriptor(packageName) {
302  return `L${packageName.replace(/\./g, '/')}`;
303}
304//# sourceMappingURL=Package.js.map