config.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.checkExternalConfig = exports.writeConfig = exports.loadConfig = exports.CONFIG_FILE_NAME_JSON = exports.CONFIG_FILE_NAME_JS = exports.CONFIG_FILE_NAME_TS = void 0;
  4. const tslib_1 = require("tslib");
  5. const utils_fs_1 = require("@ionic/utils-fs");
  6. const debug_1 = tslib_1.__importDefault(require("debug"));
  7. const path_1 = require("path");
  8. const colors_1 = tslib_1.__importDefault(require("./colors"));
  9. const common_1 = require("./common");
  10. const errors_1 = require("./errors");
  11. const log_1 = require("./log");
  12. const fn_1 = require("./util/fn");
  13. const js_1 = require("./util/js");
  14. const monorepotools_1 = require("./util/monorepotools");
  15. const node_1 = require("./util/node");
  16. const promise_1 = require("./util/promise");
  17. const subprocess_1 = require("./util/subprocess");
  18. const debug = (0, debug_1.default)('capacitor:config');
  19. exports.CONFIG_FILE_NAME_TS = 'capacitor.config.ts';
  20. exports.CONFIG_FILE_NAME_JS = 'capacitor.config.js';
  21. exports.CONFIG_FILE_NAME_JSON = 'capacitor.config.json';
  22. async function loadConfig() {
  23. var _a, _b, _c, _d;
  24. const appRootDir = process.cwd();
  25. const cliRootDir = (0, path_1.dirname)(__dirname);
  26. const conf = await loadExtConfig(appRootDir);
  27. const depsForNx = await (async () => {
  28. var _a, _b;
  29. if ((0, monorepotools_1.isNXMonorepo)(appRootDir)) {
  30. const rootOfNXMonorepo = (0, monorepotools_1.findNXMonorepoRoot)(appRootDir);
  31. const pkgJSONOfMonorepoRoot = await (0, fn_1.tryFn)(utils_fs_1.readJSON, (0, path_1.resolve)(rootOfNXMonorepo, 'package.json'));
  32. const devDependencies = (_a = pkgJSONOfMonorepoRoot === null || pkgJSONOfMonorepoRoot === void 0 ? void 0 : pkgJSONOfMonorepoRoot.devDependencies) !== null && _a !== void 0 ? _a : {};
  33. const dependencies = (_b = pkgJSONOfMonorepoRoot === null || pkgJSONOfMonorepoRoot === void 0 ? void 0 : pkgJSONOfMonorepoRoot.dependencies) !== null && _b !== void 0 ? _b : {};
  34. return {
  35. devDependencies,
  36. dependencies,
  37. };
  38. }
  39. return {};
  40. })();
  41. const appId = (_a = conf.extConfig.appId) !== null && _a !== void 0 ? _a : '';
  42. const appName = (_b = conf.extConfig.appName) !== null && _b !== void 0 ? _b : '';
  43. const webDir = (_c = conf.extConfig.webDir) !== null && _c !== void 0 ? _c : 'www';
  44. const cli = await loadCLIConfig(cliRootDir);
  45. const config = {
  46. android: await loadAndroidConfig(appRootDir, conf.extConfig, cli),
  47. ios: await loadIOSConfig(appRootDir, conf.extConfig),
  48. web: await loadWebConfig(appRootDir, webDir),
  49. cli,
  50. app: {
  51. rootDir: appRootDir,
  52. appId,
  53. appName,
  54. webDir,
  55. webDirAbs: (0, path_1.resolve)(appRootDir, webDir),
  56. package: (_d = (await (0, fn_1.tryFn)(utils_fs_1.readJSON, (0, path_1.resolve)(appRootDir, 'package.json')))) !== null && _d !== void 0 ? _d : {
  57. name: appName,
  58. version: '1.0.0',
  59. ...depsForNx,
  60. },
  61. ...conf,
  62. },
  63. };
  64. debug('config: %O', config);
  65. return config;
  66. }
  67. exports.loadConfig = loadConfig;
  68. async function writeConfig(extConfig, extConfigFilePath) {
  69. switch ((0, path_1.extname)(extConfigFilePath)) {
  70. case '.json': {
  71. await (0, utils_fs_1.writeJSON)(extConfigFilePath, extConfig, { spaces: 2 });
  72. break;
  73. }
  74. case '.ts': {
  75. await (0, utils_fs_1.writeFile)(extConfigFilePath, formatConfigTS(extConfig));
  76. break;
  77. }
  78. }
  79. }
  80. exports.writeConfig = writeConfig;
  81. async function loadExtConfigTS(rootDir, extConfigName, extConfigFilePath) {
  82. var _a;
  83. try {
  84. const tsPath = (0, node_1.resolveNode)(rootDir, 'typescript');
  85. if (!tsPath) {
  86. (0, errors_1.fatal)('Could not find installation of TypeScript.\n' +
  87. `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. }
  89. const ts = require(tsPath); // eslint-disable-line @typescript-eslint/no-var-requires
  90. const extConfigObject = (0, node_1.requireTS)(ts, extConfigFilePath);
  91. const extConfig = extConfigObject.default
  92. ? await extConfigObject.default
  93. : extConfigObject;
  94. return {
  95. extConfigType: 'ts',
  96. extConfigName,
  97. extConfigFilePath: extConfigFilePath,
  98. extConfig,
  99. };
  100. }
  101. catch (e) {
  102. if (!(0, errors_1.isFatal)(e)) {
  103. (0, errors_1.fatal)(`Parsing ${colors_1.default.strong(extConfigName)} failed.\n\n${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
  104. }
  105. throw e;
  106. }
  107. }
  108. async function loadExtConfigJS(rootDir, extConfigName, extConfigFilePath) {
  109. var _a;
  110. try {
  111. return {
  112. extConfigType: 'js',
  113. extConfigName,
  114. extConfigFilePath: extConfigFilePath,
  115. extConfig: await require(extConfigFilePath),
  116. };
  117. }
  118. catch (e) {
  119. (0, errors_1.fatal)(`Parsing ${colors_1.default.strong(extConfigName)} failed.\n\n${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
  120. }
  121. }
  122. async function loadExtConfig(rootDir) {
  123. var _a;
  124. const extConfigFilePathTS = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_TS);
  125. if (await (0, utils_fs_1.pathExists)(extConfigFilePathTS)) {
  126. return loadExtConfigTS(rootDir, exports.CONFIG_FILE_NAME_TS, extConfigFilePathTS);
  127. }
  128. const extConfigFilePathJS = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_JS);
  129. if (await (0, utils_fs_1.pathExists)(extConfigFilePathJS)) {
  130. return loadExtConfigJS(rootDir, exports.CONFIG_FILE_NAME_JS, extConfigFilePathJS);
  131. }
  132. const extConfigFilePath = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_JSON);
  133. return {
  134. extConfigType: 'json',
  135. extConfigName: exports.CONFIG_FILE_NAME_JSON,
  136. extConfigFilePath: extConfigFilePath,
  137. extConfig: (_a = (await (0, fn_1.tryFn)(utils_fs_1.readJSON, extConfigFilePath))) !== null && _a !== void 0 ? _a : {},
  138. };
  139. }
  140. async function loadCLIConfig(rootDir) {
  141. const assetsDir = 'assets';
  142. const assetsDirAbs = (0, path_1.join)(rootDir, assetsDir);
  143. const iosPlatformTemplateArchive = 'ios-pods-template.tar.gz';
  144. const iosCordovaPluginsTemplateArchive = 'capacitor-cordova-ios-plugins.tar.gz';
  145. const androidPlatformTemplateArchive = 'android-template.tar.gz';
  146. const androidCordovaPluginsTemplateArchive = 'capacitor-cordova-android-plugins.tar.gz';
  147. return {
  148. rootDir,
  149. assetsDir,
  150. assetsDirAbs,
  151. assets: {
  152. ios: {
  153. platformTemplateArchive: iosPlatformTemplateArchive,
  154. platformTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, iosPlatformTemplateArchive),
  155. cordovaPluginsTemplateArchive: iosCordovaPluginsTemplateArchive,
  156. cordovaPluginsTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, iosCordovaPluginsTemplateArchive),
  157. },
  158. android: {
  159. platformTemplateArchive: androidPlatformTemplateArchive,
  160. platformTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, androidPlatformTemplateArchive),
  161. cordovaPluginsTemplateArchive: androidCordovaPluginsTemplateArchive,
  162. cordovaPluginsTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, androidCordovaPluginsTemplateArchive),
  163. },
  164. },
  165. package: await (0, utils_fs_1.readJSON)((0, path_1.resolve)(rootDir, 'package.json')),
  166. os: determineOS(process.platform),
  167. };
  168. }
  169. async function loadAndroidConfig(rootDir, extConfig, cliConfig) {
  170. var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
  171. const name = 'android';
  172. const platformDir = (_b = (_a = extConfig.android) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : 'android';
  173. const platformDirAbs = (0, path_1.resolve)(rootDir, platformDir);
  174. const appDir = 'app';
  175. const srcDir = `${appDir}/src`;
  176. const srcMainDir = `${srcDir}/main`;
  177. const assetsDir = `${srcMainDir}/assets`;
  178. const webDir = `${assetsDir}/public`;
  179. const resDir = `${srcMainDir}/res`;
  180. let apkPath = `${appDir}/build/outputs/apk/`;
  181. const flavor = ((_c = extConfig.android) === null || _c === void 0 ? void 0 : _c.flavor) || '';
  182. if ((_d = extConfig.android) === null || _d === void 0 ? void 0 : _d.flavor) {
  183. apkPath = `${apkPath}/${(_e = extConfig.android) === null || _e === void 0 ? void 0 : _e.flavor}`;
  184. }
  185. const apkName = (0, common_1.parseApkNameFromFlavor)(flavor);
  186. const buildOutputDir = `${apkPath}/debug`;
  187. const cordovaPluginsDir = 'capacitor-cordova-android-plugins';
  188. const studioPath = (0, promise_1.lazy)(() => determineAndroidStudioPath(cliConfig.os));
  189. const buildOptions = {
  190. keystorePath: (_g = (_f = extConfig.android) === null || _f === void 0 ? void 0 : _f.buildOptions) === null || _g === void 0 ? void 0 : _g.keystorePath,
  191. keystorePassword: (_j = (_h = extConfig.android) === null || _h === void 0 ? void 0 : _h.buildOptions) === null || _j === void 0 ? void 0 : _j.keystorePassword,
  192. keystoreAlias: (_l = (_k = extConfig.android) === null || _k === void 0 ? void 0 : _k.buildOptions) === null || _l === void 0 ? void 0 : _l.keystoreAlias,
  193. keystoreAliasPassword: (_o = (_m = extConfig.android) === null || _m === void 0 ? void 0 : _m.buildOptions) === null || _o === void 0 ? void 0 : _o.keystoreAliasPassword,
  194. signingType: (_q = (_p = extConfig.android) === null || _p === void 0 ? void 0 : _p.buildOptions) === null || _q === void 0 ? void 0 : _q.signingType,
  195. releaseType: (_s = (_r = extConfig.android) === null || _r === void 0 ? void 0 : _r.buildOptions) === null || _s === void 0 ? void 0 : _s.releaseType,
  196. };
  197. return {
  198. name,
  199. minVersion: '22',
  200. studioPath,
  201. platformDir,
  202. platformDirAbs,
  203. cordovaPluginsDir,
  204. cordovaPluginsDirAbs: (0, path_1.resolve)(platformDirAbs, cordovaPluginsDir),
  205. appDir,
  206. appDirAbs: (0, path_1.resolve)(platformDirAbs, appDir),
  207. srcDir,
  208. srcDirAbs: (0, path_1.resolve)(platformDirAbs, srcDir),
  209. srcMainDir,
  210. srcMainDirAbs: (0, path_1.resolve)(platformDirAbs, srcMainDir),
  211. assetsDir,
  212. assetsDirAbs: (0, path_1.resolve)(platformDirAbs, assetsDir),
  213. webDir,
  214. webDirAbs: (0, path_1.resolve)(platformDirAbs, webDir),
  215. resDir,
  216. resDirAbs: (0, path_1.resolve)(platformDirAbs, resDir),
  217. apkName,
  218. buildOutputDir,
  219. buildOutputDirAbs: (0, path_1.resolve)(platformDirAbs, buildOutputDir),
  220. flavor,
  221. buildOptions,
  222. };
  223. }
  224. async function loadIOSConfig(rootDir, extConfig) {
  225. var _a, _b, _c, _d;
  226. const name = 'ios';
  227. const platformDir = (_b = (_a = extConfig.ios) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : 'ios';
  228. const platformDirAbs = (0, path_1.resolve)(rootDir, platformDir);
  229. const scheme = (_d = (_c = extConfig.ios) === null || _c === void 0 ? void 0 : _c.scheme) !== null && _d !== void 0 ? _d : 'App';
  230. const nativeProjectDir = 'App';
  231. const nativeProjectDirAbs = (0, path_1.resolve)(platformDirAbs, nativeProjectDir);
  232. const nativeTargetDir = `${nativeProjectDir}/App`;
  233. const nativeTargetDirAbs = (0, path_1.resolve)(platformDirAbs, nativeTargetDir);
  234. const nativeXcodeProjDir = `${nativeProjectDir}/App.xcodeproj`;
  235. const nativeXcodeProjDirAbs = (0, path_1.resolve)(platformDirAbs, nativeXcodeProjDir);
  236. const nativeXcodeWorkspaceDirAbs = (0, promise_1.lazy)(() => determineXcodeWorkspaceDirAbs(nativeProjectDirAbs));
  237. const podPath = (0, promise_1.lazy)(() => determineGemfileOrCocoapodPath(rootDir, platformDirAbs, nativeProjectDirAbs));
  238. const webDirAbs = (0, promise_1.lazy)(() => determineIOSWebDirAbs(nativeProjectDirAbs, nativeTargetDirAbs, nativeXcodeProjDirAbs));
  239. const cordovaPluginsDir = 'capacitor-cordova-ios-plugins';
  240. return {
  241. name,
  242. minVersion: '13.0',
  243. platformDir,
  244. platformDirAbs,
  245. scheme,
  246. cordovaPluginsDir,
  247. cordovaPluginsDirAbs: (0, path_1.resolve)(platformDirAbs, cordovaPluginsDir),
  248. nativeProjectDir,
  249. nativeProjectDirAbs,
  250. nativeTargetDir,
  251. nativeTargetDirAbs,
  252. nativeXcodeProjDir,
  253. nativeXcodeProjDirAbs,
  254. nativeXcodeWorkspaceDir: (0, promise_1.lazy)(async () => (0, path_1.relative)(platformDirAbs, await nativeXcodeWorkspaceDirAbs)),
  255. nativeXcodeWorkspaceDirAbs,
  256. webDir: (0, promise_1.lazy)(async () => (0, path_1.relative)(platformDirAbs, await webDirAbs)),
  257. webDirAbs,
  258. podPath,
  259. };
  260. }
  261. async function loadWebConfig(rootDir, webDir) {
  262. const platformDir = webDir;
  263. const platformDirAbs = (0, path_1.resolve)(rootDir, platformDir);
  264. return {
  265. name: 'web',
  266. platformDir,
  267. platformDirAbs,
  268. };
  269. }
  270. function determineOS(os) {
  271. switch (os) {
  272. case 'darwin':
  273. return "mac" /* OS.Mac */;
  274. case 'win32':
  275. return "windows" /* OS.Windows */;
  276. case 'linux':
  277. return "linux" /* OS.Linux */;
  278. }
  279. return "unknown" /* OS.Unknown */;
  280. }
  281. async function determineXcodeWorkspaceDirAbs(nativeProjectDirAbs) {
  282. return (0, path_1.resolve)(nativeProjectDirAbs, 'App.xcworkspace');
  283. }
  284. async function determineIOSWebDirAbs(nativeProjectDirAbs, nativeTargetDirAbs, nativeXcodeProjDirAbs) {
  285. const re = /path\s=\spublic[\s\S]+?sourceTree\s=\s([^;]+)/;
  286. const pbxprojPath = (0, path_1.resolve)(nativeXcodeProjDirAbs, 'project.pbxproj');
  287. try {
  288. const pbxproj = await (0, utils_fs_1.readFile)(pbxprojPath, { encoding: 'utf8' });
  289. const m = pbxproj.match(re);
  290. if (m && m[1] === 'SOURCE_ROOT') {
  291. log_1.logger.warn(`Using the iOS project root for the ${colors_1.default.strong('public')} directory is deprecated.\n` +
  292. `Please follow the Upgrade Guide to move ${colors_1.default.strong('public')} inside the iOS target directory: ${colors_1.default.strong('https://capacitorjs.com/docs/updating/3-0#move-public-into-the-ios-target-directory')}`);
  293. return (0, path_1.resolve)(nativeProjectDirAbs, 'public');
  294. }
  295. }
  296. catch (e) {
  297. // ignore
  298. }
  299. return (0, path_1.resolve)(nativeTargetDirAbs, 'public');
  300. }
  301. async function determineAndroidStudioPath(os) {
  302. if (process.env.CAPACITOR_ANDROID_STUDIO_PATH) {
  303. return process.env.CAPACITOR_ANDROID_STUDIO_PATH;
  304. }
  305. switch (os) {
  306. case "mac" /* OS.Mac */:
  307. return '/Applications/Android Studio.app';
  308. case "windows" /* OS.Windows */: {
  309. const { runCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./util/subprocess')));
  310. let p = 'C:\\Program Files\\Android\\Android Studio\\bin\\studio64.exe';
  311. try {
  312. if (!(await (0, utils_fs_1.pathExists)(p))) {
  313. let commandResult = await runCommand('REG', [
  314. 'QUERY',
  315. 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Android Studio',
  316. '/v',
  317. 'Path',
  318. ]);
  319. commandResult = commandResult.replace(/(\r\n|\n|\r)/gm, '');
  320. const i = commandResult.indexOf('REG_SZ');
  321. if (i > 0) {
  322. p = commandResult.substring(i + 6).trim() + '\\bin\\studio64.exe';
  323. }
  324. }
  325. }
  326. catch (e) {
  327. debug(`Error checking registry for Android Studio path: %O`, e);
  328. break;
  329. }
  330. return p;
  331. }
  332. case "linux" /* OS.Linux */:
  333. return '/usr/local/android-studio/bin/studio.sh';
  334. }
  335. return '';
  336. }
  337. async function determineGemfileOrCocoapodPath(rootDir, platformDir, nativeProjectDirAbs) {
  338. if (process.env.CAPACITOR_COCOAPODS_PATH) {
  339. return process.env.CAPACITOR_COCOAPODS_PATH;
  340. }
  341. let gemfilePath = '';
  342. if (await (0, utils_fs_1.pathExists)((0, path_1.resolve)(rootDir, 'Gemfile'))) {
  343. gemfilePath = (0, path_1.resolve)(rootDir, 'Gemfile');
  344. }
  345. else if (await (0, utils_fs_1.pathExists)((0, path_1.resolve)(platformDir, 'Gemfile'))) {
  346. gemfilePath = (0, path_1.resolve)(platformDir, 'Gemfile');
  347. }
  348. else if (await (0, utils_fs_1.pathExists)((0, path_1.resolve)(nativeProjectDirAbs, 'Gemfile'))) {
  349. gemfilePath = (0, path_1.resolve)(nativeProjectDirAbs, 'Gemfile');
  350. }
  351. const appSpecificGemfileExists = gemfilePath != '';
  352. // Multi-app projects might share a single global 'Gemfile' at the Git repository root directory.
  353. if (!appSpecificGemfileExists) {
  354. try {
  355. const output = await (0, subprocess_1.getCommandOutput)('git', ['rev-parse', '--show-toplevel'], { cwd: rootDir });
  356. if (output != null) {
  357. gemfilePath = (0, path_1.resolve)(output, 'Gemfile');
  358. }
  359. }
  360. catch (e) {
  361. // Nothing
  362. }
  363. }
  364. try {
  365. const gemfileText = (await (0, utils_fs_1.readFile)(gemfilePath)).toString();
  366. if (!gemfileText) {
  367. return 'pod';
  368. }
  369. const cocoapodsInGemfile = new RegExp(/gem\s+['"]cocoapods/).test(gemfileText);
  370. if (cocoapodsInGemfile) {
  371. return 'bundle exec pod';
  372. }
  373. else {
  374. return 'pod';
  375. }
  376. }
  377. catch {
  378. return 'pod';
  379. }
  380. }
  381. function formatConfigTS(extConfig) {
  382. // TODO: <reference> tags
  383. return `import type { CapacitorConfig } from '@capacitor/cli';
  384. const config: CapacitorConfig = ${(0, js_1.formatJSObject)(extConfig)};
  385. export default config;\n`;
  386. }
  387. function checkExternalConfig(config) {
  388. if (typeof config.extConfig.bundledWebRuntime !== 'undefined') {
  389. let actionMessage = `Can be safely deleted.`;
  390. if (config.extConfig.bundledWebRuntime === true) {
  391. actionMessage = `Please, use a bundler to bundle Capacitor and its plugins.`;
  392. }
  393. log_1.logger.warn(`The ${colors_1.default.strong('bundledWebRuntime')} configuration option has been deprecated. ${actionMessage}`);
  394. }
  395. }
  396. exports.checkExternalConfig = checkExternalConfig;