@capacitor-plus/cli 8.0.0-beta.0

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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -0
  3. package/assets/android-template.tar.gz +0 -0
  4. package/assets/capacitor-cordova-android-plugins.tar.gz +0 -0
  5. package/assets/capacitor-cordova-ios-plugins.tar.gz +0 -0
  6. package/assets/ios-pods-template.tar.gz +0 -0
  7. package/assets/ios-spm-template.tar.gz +0 -0
  8. package/bin/capacitor +18 -0
  9. package/dist/android/add.js +52 -0
  10. package/dist/android/build.js +104 -0
  11. package/dist/android/common.js +94 -0
  12. package/dist/android/doctor.js +160 -0
  13. package/dist/android/open.js +28 -0
  14. package/dist/android/run.js +42 -0
  15. package/dist/android/update.js +317 -0
  16. package/dist/colors.js +26 -0
  17. package/dist/common.js +435 -0
  18. package/dist/config.js +404 -0
  19. package/dist/cordova.js +801 -0
  20. package/dist/declarations.d.ts +674 -0
  21. package/dist/declarations.js +2 -0
  22. package/dist/definitions.js +13 -0
  23. package/dist/errors.js +27 -0
  24. package/dist/framework-configs.js +109 -0
  25. package/dist/index.js +253 -0
  26. package/dist/ios/add.js +13 -0
  27. package/dist/ios/build.js +96 -0
  28. package/dist/ios/common.js +105 -0
  29. package/dist/ios/doctor.js +45 -0
  30. package/dist/ios/open.js +17 -0
  31. package/dist/ios/run.js +51 -0
  32. package/dist/ios/update.js +449 -0
  33. package/dist/ipc.js +61 -0
  34. package/dist/log.js +39 -0
  35. package/dist/plugin.js +182 -0
  36. package/dist/sysconfig.js +35 -0
  37. package/dist/tasks/add.js +115 -0
  38. package/dist/tasks/build.js +63 -0
  39. package/dist/tasks/config.js +28 -0
  40. package/dist/tasks/copy.js +210 -0
  41. package/dist/tasks/create.js +10 -0
  42. package/dist/tasks/doctor.js +68 -0
  43. package/dist/tasks/init.js +138 -0
  44. package/dist/tasks/list.js +50 -0
  45. package/dist/tasks/migrate-spm.js +19 -0
  46. package/dist/tasks/migrate.js +518 -0
  47. package/dist/tasks/new-plugin.js +10 -0
  48. package/dist/tasks/open.js +62 -0
  49. package/dist/tasks/run.js +118 -0
  50. package/dist/tasks/serve.js +11 -0
  51. package/dist/tasks/sourcemaps.js +39 -0
  52. package/dist/tasks/sync.js +55 -0
  53. package/dist/tasks/telemetry.js +41 -0
  54. package/dist/tasks/update.js +74 -0
  55. package/dist/telemetry.js +119 -0
  56. package/dist/util/cli.js +25 -0
  57. package/dist/util/emoji.js +13 -0
  58. package/dist/util/fn.js +13 -0
  59. package/dist/util/fs.js +43 -0
  60. package/dist/util/iosplugin.js +66 -0
  61. package/dist/util/js.js +21 -0
  62. package/dist/util/livereload.js +148 -0
  63. package/dist/util/monorepotools.js +109 -0
  64. package/dist/util/native-run.js +63 -0
  65. package/dist/util/node.js +54 -0
  66. package/dist/util/promise.js +35 -0
  67. package/dist/util/spm.js +187 -0
  68. package/dist/util/subprocess.js +37 -0
  69. package/dist/util/template.js +11 -0
  70. package/dist/util/term.js +30 -0
  71. package/dist/util/uuid.js +11 -0
  72. package/dist/util/xml.js +55 -0
  73. package/package.json +89 -0
@@ -0,0 +1,801 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeCordovaAndroidManifest = exports.getCordovaPreferences = exports.needsStaticPod = exports.getIncompatibleCordovaPlugins = exports.checkPluginDependencies = exports.logCordovaManualSteps = exports.getCordovaPlugins = exports.handleCordovaPluginsJS = exports.autoGenerateConfig = exports.removePluginFiles = exports.createEmptyCordovaJS = exports.copyCordovaJS = exports.copyPluginsJS = exports.generateCordovaPluginsJSFile = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_extra_1 = require("fs-extra");
6
+ const path_1 = require("path");
7
+ const plist_1 = tslib_1.__importDefault(require("plist"));
8
+ const prompts_1 = tslib_1.__importDefault(require("prompts"));
9
+ const common_1 = require("./android/common");
10
+ const colors_1 = tslib_1.__importDefault(require("./colors"));
11
+ const errors_1 = require("./errors");
12
+ const common_2 = require("./ios/common");
13
+ const log_1 = require("./log");
14
+ const plugin_1 = require("./plugin");
15
+ const node_1 = require("./util/node");
16
+ const term_1 = require("./util/term");
17
+ const xml_1 = require("./util/xml");
18
+ /**
19
+ * Build the root cordova_plugins.js file referencing each Plugin JS file.
20
+ */
21
+ function generateCordovaPluginsJSFile(config, plugins, platform) {
22
+ const pluginModules = [];
23
+ const pluginExports = [];
24
+ plugins.map((p) => {
25
+ const pluginId = p.xml.$.id;
26
+ const jsModules = (0, plugin_1.getJSModules)(p, platform);
27
+ jsModules.map((jsModule) => {
28
+ const clobbers = [];
29
+ const merges = [];
30
+ let clobbersModule = '';
31
+ let mergesModule = '';
32
+ let runsModule = '';
33
+ let clobberKey = '';
34
+ let mergeKey = '';
35
+ if (jsModule.clobbers) {
36
+ jsModule.clobbers.map((clobber) => {
37
+ clobbers.push(clobber.$.target);
38
+ clobberKey = clobber.$.target;
39
+ });
40
+ clobbersModule = `,
41
+ "clobbers": [
42
+ "${clobbers.join('",\n "')}"
43
+ ]`;
44
+ }
45
+ if (jsModule.merges) {
46
+ jsModule.merges.map((merge) => {
47
+ merges.push(merge.$.target);
48
+ mergeKey = merge.$.target;
49
+ });
50
+ mergesModule = `,
51
+ "merges": [
52
+ "${merges.join('",\n "')}"
53
+ ]`;
54
+ }
55
+ if (jsModule.runs) {
56
+ runsModule = ',\n "runs": true';
57
+ }
58
+ const pluginModule = {
59
+ clobber: clobberKey,
60
+ merge: mergeKey,
61
+ // mimics Cordova's module name logic if the name attr is missing
62
+ pluginContent: `{
63
+ "id": "${pluginId + '.' + (jsModule.$.name || jsModule.$.src.match(/([^/]+)\.js/)[1])}",
64
+ "file": "plugins/${pluginId}/${jsModule.$.src}",
65
+ "pluginId": "${pluginId}"${clobbersModule}${mergesModule}${runsModule}
66
+ }`,
67
+ };
68
+ pluginModules.push(pluginModule);
69
+ });
70
+ pluginExports.push(`"${pluginId}": "${p.xml.$.version}"`);
71
+ });
72
+ return `
73
+ cordova.define('cordova/plugin_list', function(require, exports, module) {
74
+ module.exports = [
75
+ ${pluginModules
76
+ .sort((a, b) => a.clobber && b.clobber // Clobbers in alpha order
77
+ ? a.clobber.localeCompare(b.clobber)
78
+ : a.clobber || b.clobber // Clobbers before anything else
79
+ ? b.clobber.localeCompare(a.clobber)
80
+ : a.merge.localeCompare(b.merge))
81
+ .map((e) => e.pluginContent)
82
+ .join(',\n ')}
83
+ ];
84
+ module.exports.metadata =
85
+ // TOP OF METADATA
86
+ {
87
+ ${pluginExports.join(',\n ')}
88
+ };
89
+ // BOTTOM OF METADATA
90
+ });
91
+ `;
92
+ }
93
+ exports.generateCordovaPluginsJSFile = generateCordovaPluginsJSFile;
94
+ /**
95
+ * Build the plugins/* files for each Cordova plugin installed.
96
+ */
97
+ async function copyPluginsJS(config, cordovaPlugins, platform) {
98
+ const webDir = await getWebDir(config, platform);
99
+ const pluginsDir = (0, path_1.join)(webDir, 'plugins');
100
+ const cordovaPluginsJSFile = (0, path_1.join)(webDir, 'cordova_plugins.js');
101
+ await removePluginFiles(config, platform);
102
+ await Promise.all(cordovaPlugins.map(async (p) => {
103
+ const pluginId = p.xml.$.id;
104
+ const pluginDir = (0, path_1.join)(pluginsDir, pluginId, 'www');
105
+ await (0, fs_extra_1.ensureDir)(pluginDir);
106
+ const jsModules = (0, plugin_1.getJSModules)(p, platform);
107
+ await Promise.all(jsModules.map(async (jsModule) => {
108
+ const filePath = (0, path_1.join)(webDir, 'plugins', pluginId, jsModule.$.src);
109
+ await (0, fs_extra_1.copy)((0, path_1.join)(p.rootPath, jsModule.$.src), filePath);
110
+ let data = await (0, fs_extra_1.readFile)(filePath, { encoding: 'utf-8' });
111
+ data = data.trim();
112
+ // mimics Cordova's module name logic if the name attr is missing
113
+ const name = pluginId + '.' + (jsModule.$.name || (0, path_1.basename)(jsModule.$.src, (0, path_1.extname)(jsModule.$.src)));
114
+ data = `cordova.define("${name}", function(require, exports, module) { \n${data}\n});`;
115
+ data = data.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script\s*>/gi, '');
116
+ await (0, fs_extra_1.writeFile)(filePath, data, { encoding: 'utf-8' });
117
+ }));
118
+ const assets = (0, plugin_1.getAssets)(p, platform);
119
+ await Promise.all(assets.map(async (asset) => {
120
+ const filePath = (0, path_1.join)(webDir, asset.$.target);
121
+ await (0, fs_extra_1.copy)((0, path_1.join)(p.rootPath, asset.$.src), filePath);
122
+ }));
123
+ }));
124
+ await (0, fs_extra_1.writeFile)(cordovaPluginsJSFile, generateCordovaPluginsJSFile(config, cordovaPlugins, platform));
125
+ }
126
+ exports.copyPluginsJS = copyPluginsJS;
127
+ async function copyCordovaJS(config, platform) {
128
+ const cordovaPath = (0, node_1.resolveNode)(config.app.rootDir, '@capacitor/core', 'cordova.js');
129
+ if (!cordovaPath) {
130
+ (0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/core/cordova.js')}.\n` +
131
+ `Are you sure ${colors_1.default.strong('@capacitor/core')} is installed?`);
132
+ }
133
+ return (0, fs_extra_1.copy)(cordovaPath, (0, path_1.join)(await getWebDir(config, platform), 'cordova.js'));
134
+ }
135
+ exports.copyCordovaJS = copyCordovaJS;
136
+ async function createEmptyCordovaJS(config, platform) {
137
+ const webDir = await getWebDir(config, platform);
138
+ await (0, fs_extra_1.writeFile)((0, path_1.join)(webDir, 'cordova.js'), '');
139
+ await (0, fs_extra_1.writeFile)((0, path_1.join)(webDir, 'cordova_plugins.js'), '');
140
+ }
141
+ exports.createEmptyCordovaJS = createEmptyCordovaJS;
142
+ async function removePluginFiles(config, platform) {
143
+ const webDir = await getWebDir(config, platform);
144
+ const pluginsDir = (0, path_1.join)(webDir, 'plugins');
145
+ const cordovaPluginsJSFile = (0, path_1.join)(webDir, 'cordova_plugins.js');
146
+ await (0, fs_extra_1.remove)(pluginsDir);
147
+ await (0, fs_extra_1.remove)(cordovaPluginsJSFile);
148
+ }
149
+ exports.removePluginFiles = removePluginFiles;
150
+ async function autoGenerateConfig(config, cordovaPlugins, platform) {
151
+ var _a, _b, _c, _d;
152
+ let xmlDir = (0, path_1.join)(config.android.resDirAbs, 'xml');
153
+ const fileName = 'config.xml';
154
+ if (platform === 'ios') {
155
+ xmlDir = config.ios.nativeTargetDirAbs;
156
+ }
157
+ await (0, fs_extra_1.ensureDir)(xmlDir);
158
+ const cordovaConfigXMLFile = (0, path_1.join)(xmlDir, fileName);
159
+ await (0, fs_extra_1.remove)(cordovaConfigXMLFile);
160
+ const pluginEntries = [];
161
+ cordovaPlugins.map((p) => {
162
+ const currentPlatform = (0, plugin_1.getPluginPlatform)(p, platform);
163
+ if (currentPlatform) {
164
+ const configFiles = currentPlatform['config-file'];
165
+ if (configFiles) {
166
+ const configXMLEntries = configFiles.filter(function (item) {
167
+ var _a;
168
+ return (_a = item.$) === null || _a === void 0 ? void 0 : _a.target.includes(fileName);
169
+ });
170
+ configXMLEntries.map((entry) => {
171
+ if (entry.feature) {
172
+ const feature = { feature: entry.feature };
173
+ pluginEntries.push(feature);
174
+ }
175
+ });
176
+ }
177
+ }
178
+ });
179
+ let accessOriginString = [];
180
+ if ((_b = (_a = config.app.extConfig) === null || _a === void 0 ? void 0 : _a.cordova) === null || _b === void 0 ? void 0 : _b.accessOrigins) {
181
+ accessOriginString = await Promise.all(config.app.extConfig.cordova.accessOrigins.map(async (host) => {
182
+ return `
183
+ <access origin="${host}" />`;
184
+ }));
185
+ }
186
+ else {
187
+ accessOriginString.push(`<access origin="*" />`);
188
+ }
189
+ const pluginEntriesString = await Promise.all(pluginEntries.map(async (item) => {
190
+ const xmlString = await (0, xml_1.writeXML)(item);
191
+ return xmlString;
192
+ }));
193
+ let pluginPreferencesString = [];
194
+ if ((_d = (_c = config.app.extConfig) === null || _c === void 0 ? void 0 : _c.cordova) === null || _d === void 0 ? void 0 : _d.preferences) {
195
+ pluginPreferencesString = await Promise.all(Object.entries(config.app.extConfig.cordova.preferences).map(async ([key, value]) => {
196
+ return `
197
+ <preference name="${key}" value="${value}" />`;
198
+ }));
199
+ }
200
+ const content = `<?xml version='1.0' encoding='utf-8'?>
201
+ <widget version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
202
+ ${accessOriginString.join('')}
203
+ ${pluginEntriesString.join('')}
204
+ ${pluginPreferencesString.join('')}
205
+ </widget>`;
206
+ await (0, fs_extra_1.writeFile)(cordovaConfigXMLFile, content);
207
+ }
208
+ exports.autoGenerateConfig = autoGenerateConfig;
209
+ async function getWebDir(config, platform) {
210
+ if (platform === 'ios') {
211
+ return config.ios.webDirAbs;
212
+ }
213
+ if (platform === 'android') {
214
+ return config.android.webDirAbs;
215
+ }
216
+ return '';
217
+ }
218
+ async function handleCordovaPluginsJS(cordovaPlugins, config, platform) {
219
+ const webDir = await getWebDir(config, platform);
220
+ await (0, fs_extra_1.mkdirp)(webDir);
221
+ if (cordovaPlugins.length > 0) {
222
+ (0, plugin_1.printPlugins)(cordovaPlugins, platform, 'cordova');
223
+ await copyCordovaJS(config, platform);
224
+ await copyPluginsJS(config, cordovaPlugins, platform);
225
+ }
226
+ else {
227
+ await removePluginFiles(config, platform);
228
+ await createEmptyCordovaJS(config, platform);
229
+ }
230
+ await autoGenerateConfig(config, cordovaPlugins, platform);
231
+ }
232
+ exports.handleCordovaPluginsJS = handleCordovaPluginsJS;
233
+ async function getCordovaPlugins(config, platform) {
234
+ const allPlugins = await (0, plugin_1.getPlugins)(config, platform);
235
+ let plugins = [];
236
+ if (platform === config.ios.name) {
237
+ plugins = await (0, common_2.getIOSPlugins)(allPlugins);
238
+ }
239
+ else if (platform === config.android.name) {
240
+ plugins = await (0, common_1.getAndroidPlugins)(allPlugins);
241
+ }
242
+ return plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
243
+ }
244
+ exports.getCordovaPlugins = getCordovaPlugins;
245
+ async function logCordovaManualSteps(cordovaPlugins, config, platform) {
246
+ cordovaPlugins.map((p) => {
247
+ const editConfig = (0, plugin_1.getPlatformElement)(p, platform, 'edit-config');
248
+ const configFile = (0, plugin_1.getPlatformElement)(p, platform, 'config-file');
249
+ editConfig.concat(configFile).map(async (configElement) => {
250
+ if (configElement.$ && !configElement.$.target.includes('config.xml')) {
251
+ if (platform === config.ios.name) {
252
+ if (configElement.$.target.includes('Info.plist')) {
253
+ logiOSPlist(configElement, config, p);
254
+ }
255
+ }
256
+ }
257
+ });
258
+ });
259
+ }
260
+ exports.logCordovaManualSteps = logCordovaManualSteps;
261
+ async function logiOSPlist(configElement, config, plugin) {
262
+ var _a, _b;
263
+ let plistPath = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist');
264
+ if ((_a = config.app.extConfig.ios) === null || _a === void 0 ? void 0 : _a.scheme) {
265
+ plistPath = (0, path_1.resolve)(config.ios.nativeProjectDirAbs, `${(_b = config.app.extConfig.ios) === null || _b === void 0 ? void 0 : _b.scheme}-Info.plist`);
266
+ }
267
+ if (!(await (0, fs_extra_1.pathExists)(plistPath))) {
268
+ plistPath = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Base.lproj', 'Info.plist');
269
+ }
270
+ if (await (0, fs_extra_1.pathExists)(plistPath)) {
271
+ const xmlMeta = await (0, xml_1.readXML)(plistPath);
272
+ const data = await (0, fs_extra_1.readFile)(plistPath, { encoding: 'utf-8' });
273
+ const trimmedPlistData = data.replace(/(\t|\r|\n)/g, '');
274
+ const plistData = plist_1.default.parse(data);
275
+ const dict = xmlMeta.plist.dict.pop();
276
+ if (!dict.key.includes(configElement.$.parent)) {
277
+ let xml = buildConfigFileXml(configElement);
278
+ xml = `<key>${configElement.$.parent}</key>${getConfigFileTagContent(xml)}`;
279
+ log_1.logger.warn(`Configuration required for ${colors_1.default.strong(plugin.id)}.\n` + `Add the following to Info.plist:\n` + xml);
280
+ }
281
+ else if (configElement.array || configElement.dict) {
282
+ if (configElement.array && configElement.array.length > 0 && configElement.array[0].string) {
283
+ let xml = '';
284
+ configElement.array[0].string.map((element) => {
285
+ const d = plistData[configElement.$.parent];
286
+ if (Array.isArray(d) && !d.includes(element)) {
287
+ xml = xml.concat(`<string>${element}</string>\n`);
288
+ }
289
+ });
290
+ if (xml.length > 0) {
291
+ log_1.logger.warn(`Configuration required for ${colors_1.default.strong(plugin.id)}.\n` +
292
+ `Add the following in the existing ${colors_1.default.strong(configElement.$.parent)} array of your Info.plist:\n` +
293
+ xml);
294
+ }
295
+ }
296
+ else {
297
+ let xml = buildConfigFileXml(configElement);
298
+ xml = `<key>${configElement.$.parent}</key>${getConfigFileTagContent(xml)}`;
299
+ xml = `<plist version="1.0"><dict>${xml}</dict></plist>`;
300
+ const parseXmlToSearchable = (childElementsObj, arrayToAddTo) => {
301
+ for (const childElement of childElementsObj) {
302
+ const childElementName = childElement['#name'];
303
+ const toAdd = { name: childElementName };
304
+ if (childElementName === 'key' || childElementName === 'string') {
305
+ toAdd.value = childElement['_'];
306
+ }
307
+ else {
308
+ if (childElement['$']) {
309
+ toAdd.attrs = { ...childElement['$'] };
310
+ }
311
+ if (childElement['$$']) {
312
+ toAdd.children = [];
313
+ parseXmlToSearchable(childElement['$$'], toAdd['children']);
314
+ }
315
+ }
316
+ arrayToAddTo.push(toAdd);
317
+ }
318
+ };
319
+ const existingElements = (0, xml_1.parseXML)(trimmedPlistData, {
320
+ explicitChildren: true,
321
+ trim: true,
322
+ preserveChildrenOrder: true,
323
+ });
324
+ const parsedExistingElements = [];
325
+ const rootKeyOfExistingElements = Object.keys(existingElements)[0];
326
+ const rootOfExistingElementsToAdd = { name: rootKeyOfExistingElements, children: [] };
327
+ if (existingElements[rootKeyOfExistingElements]['$']) {
328
+ rootOfExistingElementsToAdd.attrs = {
329
+ ...existingElements[rootKeyOfExistingElements]['$'],
330
+ };
331
+ }
332
+ parseXmlToSearchable(existingElements[rootKeyOfExistingElements]['$$'], rootOfExistingElementsToAdd['children']);
333
+ parsedExistingElements.push(rootOfExistingElementsToAdd);
334
+ const requiredElements = (0, xml_1.parseXML)(xml, {
335
+ explicitChildren: true,
336
+ trim: true,
337
+ preserveChildrenOrder: true,
338
+ });
339
+ const parsedRequiredElements = [];
340
+ const rootKeyOfRequiredElements = Object.keys(requiredElements)[0];
341
+ const rootOfRequiredElementsToAdd = { name: rootKeyOfRequiredElements, children: [] };
342
+ if (requiredElements[rootKeyOfRequiredElements]['$']) {
343
+ rootOfRequiredElementsToAdd.attrs = {
344
+ ...requiredElements[rootKeyOfRequiredElements]['$'],
345
+ };
346
+ }
347
+ parseXmlToSearchable(requiredElements[rootKeyOfRequiredElements]['$$'], rootOfRequiredElementsToAdd['children']);
348
+ parsedRequiredElements.push(rootOfRequiredElementsToAdd);
349
+ const doesContainElements = (requiredElementsArray, existingElementsArray) => {
350
+ for (const requiredElement of requiredElementsArray) {
351
+ if (requiredElement.name === 'key' || requiredElement.name === 'string') {
352
+ let foundMatch = false;
353
+ for (const existingElement of existingElementsArray) {
354
+ if (existingElement.name === requiredElement.name &&
355
+ (existingElement.value === requiredElement.value ||
356
+ /^[$].{1,}$/.test(requiredElement.value.trim()))) {
357
+ foundMatch = true;
358
+ break;
359
+ }
360
+ }
361
+ if (!foundMatch) {
362
+ return false;
363
+ }
364
+ }
365
+ else {
366
+ let foundMatch = false;
367
+ for (const existingElement of existingElementsArray) {
368
+ if (existingElement.name === requiredElement.name) {
369
+ if ((requiredElement.children !== undefined) === (existingElement.children !== undefined)) {
370
+ if (doesContainElements(requiredElement.children, existingElement.children)) {
371
+ foundMatch = true;
372
+ break;
373
+ }
374
+ }
375
+ }
376
+ }
377
+ if (!foundMatch) {
378
+ return false;
379
+ }
380
+ }
381
+ }
382
+ return true;
383
+ };
384
+ if (!doesContainElements(parsedRequiredElements, parsedExistingElements)) {
385
+ logPossibleMissingItem(configElement, plugin);
386
+ }
387
+ }
388
+ }
389
+ }
390
+ else {
391
+ logPossibleMissingItem(configElement, plugin);
392
+ }
393
+ }
394
+ function logPossibleMissingItem(configElement, plugin) {
395
+ let xml = buildConfigFileXml(configElement);
396
+ xml = getConfigFileTagContent(xml);
397
+ xml = removeOuterTags(xml);
398
+ log_1.logger.warn(`Configuration might be missing for ${colors_1.default.strong(plugin.id)}.\n` +
399
+ `Add the following to the existing ${colors_1.default.strong(configElement.$.parent)} entry of Info.plist:\n` +
400
+ xml);
401
+ }
402
+ function buildConfigFileXml(configElement) {
403
+ return (0, xml_1.buildXmlElement)(configElement, 'config-file');
404
+ }
405
+ function getConfigFileTagContent(str) {
406
+ return str.replace(/<config-file.+">|<\/config-file>/g, '');
407
+ }
408
+ function removeOuterTags(str) {
409
+ const start = str.indexOf('>') + 1;
410
+ const end = str.lastIndexOf('<');
411
+ return str.substring(start, end);
412
+ }
413
+ async function checkPluginDependencies(plugins, platform, failOnMissingDeps = false) {
414
+ const pluginDeps = new Map();
415
+ const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
416
+ const incompatible = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */);
417
+ await Promise.all(cordovaPlugins.map(async (p) => {
418
+ let allDependencies = [];
419
+ allDependencies = allDependencies.concat((0, plugin_1.getPlatformElement)(p, platform, 'dependency'));
420
+ if (p.xml['dependency']) {
421
+ allDependencies = allDependencies.concat(p.xml['dependency']);
422
+ }
423
+ allDependencies = allDependencies.filter((dep) => !getIncompatibleCordovaPlugins(platform).includes(dep.$.id) &&
424
+ incompatible.filter((p) => p.id === dep.$.id || p.xml.$.id === dep.$.id).length === 0);
425
+ if (allDependencies) {
426
+ await Promise.all(allDependencies.map(async (dep) => {
427
+ var _a;
428
+ let plugin = dep.$.id;
429
+ let version = dep.$.version;
430
+ if (plugin.includes('@') && plugin.indexOf('@') !== 0) {
431
+ [plugin, version] = plugin.split('@');
432
+ }
433
+ if (cordovaPlugins.filter((p) => p.id === plugin || p.xml.$.id === plugin).length === 0) {
434
+ if ((_a = dep.$.url) === null || _a === void 0 ? void 0 : _a.startsWith('http')) {
435
+ plugin = dep.$.url;
436
+ version = dep.$.commit;
437
+ }
438
+ const deps = pluginDeps.get(p.id) || [];
439
+ deps.push(`${plugin}${version ? colors_1.default.weak(` (${version})`) : ''}`);
440
+ pluginDeps.set(p.id, deps);
441
+ }
442
+ }));
443
+ }
444
+ }));
445
+ if (pluginDeps.size > 0) {
446
+ let msg = `${colors_1.default.failure(colors_1.default.strong('Plugins are missing dependencies.'))}\n` +
447
+ `Cordova plugin dependencies must be installed in your project (e.g. w/ ${colors_1.default.input('npm install')}).\n`;
448
+ for (const [plugin, deps] of pluginDeps.entries()) {
449
+ msg += `\n ${colors_1.default.strong(plugin)} is missing dependencies:\n` + deps.map((d) => ` - ${d}`).join('\n');
450
+ }
451
+ if (failOnMissingDeps) {
452
+ (0, errors_1.fatal)(`${msg}\n`);
453
+ }
454
+ log_1.logger.warn(`${msg}\n`);
455
+ }
456
+ }
457
+ exports.checkPluginDependencies = checkPluginDependencies;
458
+ function getIncompatibleCordovaPlugins(platform) {
459
+ const pluginList = [
460
+ 'cordova-plugin-splashscreen',
461
+ 'cordova-plugin-ionic-webview',
462
+ 'cordova-plugin-crosswalk-webview',
463
+ 'cordova-plugin-wkwebview-engine',
464
+ 'cordova-plugin-console',
465
+ 'cordova-plugin-music-controls',
466
+ 'cordova-plugin-add-swift-support',
467
+ 'cordova-plugin-ionic-keyboard',
468
+ 'cordova-plugin-braintree',
469
+ '@ionic-enterprise/filesystem',
470
+ '@ionic-enterprise/keyboard',
471
+ '@ionic-enterprise/splashscreen',
472
+ 'cordova-support-google-services',
473
+ ];
474
+ if (platform === 'ios') {
475
+ pluginList.push('cordova-plugin-statusbar', '@ionic-enterprise/statusbar', 'SalesforceMobileSDK-CordovaPlugin');
476
+ }
477
+ if (platform === 'android') {
478
+ pluginList.push('cordova-plugin-compat');
479
+ }
480
+ return pluginList;
481
+ }
482
+ exports.getIncompatibleCordovaPlugins = getIncompatibleCordovaPlugins;
483
+ function needsStaticPod(plugin) {
484
+ return useFrameworks(plugin);
485
+ }
486
+ exports.needsStaticPod = needsStaticPod;
487
+ function useFrameworks(plugin) {
488
+ const podspecs = (0, plugin_1.getPlatformElement)(plugin, 'ios', 'podspec');
489
+ const frameworkPods = podspecs.filter((podspec) => podspec.pods.filter((pods) => pods.$ && pods.$['use-frameworks'] === 'true').length > 0);
490
+ return frameworkPods.length > 0;
491
+ }
492
+ async function getCordovaPreferences(config) {
493
+ var _a, _b, _c, _d, _e;
494
+ const configXml = (0, path_1.join)(config.app.rootDir, 'config.xml');
495
+ let cordova = {};
496
+ if (await (0, fs_extra_1.pathExists)(configXml)) {
497
+ cordova.preferences = {};
498
+ const xmlMeta = await (0, xml_1.readXML)(configXml);
499
+ if (xmlMeta.widget.preference) {
500
+ xmlMeta.widget.preference.map((pref) => {
501
+ cordova.preferences[pref.$.name] = pref.$.value;
502
+ });
503
+ }
504
+ }
505
+ if (cordova.preferences && Object.keys(cordova.preferences).length > 0) {
506
+ if ((0, term_1.isInteractive)()) {
507
+ const answers = await (0, log_1.logPrompt)(`${colors_1.default.strong(`Cordova preferences can be automatically ported to ${colors_1.default.strong(config.app.extConfigName)}.`)}\n` +
508
+ `Keep in mind: Not all values can be automatically migrated from ${colors_1.default.strong('config.xml')}. There may be more work to do.\n` +
509
+ `More info: ${colors_1.default.strong('https://capacitorjs.com/docs/cordova/migrating-from-cordova-to-capacitor')}`, {
510
+ type: 'confirm',
511
+ name: 'confirm',
512
+ message: `Migrate Cordova preferences from config.xml?`,
513
+ initial: true,
514
+ });
515
+ if (answers.confirm) {
516
+ if ((_b = (_a = config.app.extConfig) === null || _a === void 0 ? void 0 : _a.cordova) === null || _b === void 0 ? void 0 : _b.preferences) {
517
+ const answers = await (0, prompts_1.default)([
518
+ {
519
+ type: 'confirm',
520
+ name: 'confirm',
521
+ message: `${config.app.extConfigName} already contains Cordova preferences. Overwrite?`,
522
+ },
523
+ ], { onCancel: () => process.exit(1) });
524
+ if (!answers.confirm) {
525
+ cordova = (_c = config.app.extConfig) === null || _c === void 0 ? void 0 : _c.cordova;
526
+ }
527
+ }
528
+ }
529
+ else {
530
+ cordova = (_d = config.app.extConfig) === null || _d === void 0 ? void 0 : _d.cordova;
531
+ }
532
+ }
533
+ }
534
+ else {
535
+ cordova = (_e = config.app.extConfig) === null || _e === void 0 ? void 0 : _e.cordova;
536
+ }
537
+ return cordova;
538
+ }
539
+ exports.getCordovaPreferences = getCordovaPreferences;
540
+ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cleartext) {
541
+ var _a;
542
+ const manifestPath = (0, path_1.join)(config.android.cordovaPluginsDirAbs, 'src', 'main', 'AndroidManifest.xml');
543
+ const rootXMLEntries = [];
544
+ const applicationXMLEntries = [];
545
+ const applicationXMLAttributes = [];
546
+ let prefsArray = [];
547
+ cordovaPlugins.map(async (p) => {
548
+ const editConfig = (0, plugin_1.getPlatformElement)(p, platform, 'edit-config');
549
+ const configFile = (0, plugin_1.getPlatformElement)(p, platform, 'config-file');
550
+ prefsArray = prefsArray.concat((0, plugin_1.getAllElements)(p, platform, 'preference'));
551
+ editConfig.concat(configFile).map(async (configElement) => {
552
+ var _a, _b;
553
+ if (configElement.$ &&
554
+ (((_a = configElement.$.target) === null || _a === void 0 ? void 0 : _a.includes('AndroidManifest.xml')) ||
555
+ ((_b = configElement.$.file) === null || _b === void 0 ? void 0 : _b.includes('AndroidManifest.xml')))) {
556
+ const keys = Object.keys(configElement).filter((k) => k !== '$');
557
+ keys.map((k) => {
558
+ configElement[k].map(async (e) => {
559
+ const xmlElement = (0, xml_1.buildXmlElement)(e, k);
560
+ const pathParts = getPathParts(configElement.$.parent || configElement.$.target);
561
+ if (pathParts.length > 1) {
562
+ if (pathParts.pop() === 'application') {
563
+ if (configElement.$.mode && configElement.$.mode === 'merge' && xmlElement.startsWith('<application')) {
564
+ Object.keys(e.$).map((ek) => {
565
+ applicationXMLAttributes.push(`${ek}="${e.$[ek]}"`);
566
+ });
567
+ }
568
+ else if (!applicationXMLEntries.includes(xmlElement) &&
569
+ !contains(applicationXMLEntries, xmlElement, k)) {
570
+ applicationXMLEntries.push(xmlElement);
571
+ }
572
+ }
573
+ else {
574
+ const manifestPathOfCapApp = (0, path_1.join)(config.android.appDirAbs, 'src', 'main', 'AndroidManifest.xml');
575
+ const manifestContentTrimmed = (await (0, fs_extra_1.readFile)(manifestPathOfCapApp))
576
+ .toString()
577
+ .trim()
578
+ .replace(/\n|\t|\r/g, '')
579
+ .replace(/[\s]{1,}</g, '<')
580
+ .replace(/>[\s]{1,}/g, '>')
581
+ .replace(/[\s]{2,}/g, ' ');
582
+ const requiredManifestContentTrimmed = xmlElement
583
+ .trim()
584
+ .replace(/\n|\t|\r/g, '')
585
+ .replace(/[\s]{1,}</g, '<')
586
+ .replace(/>[\s]{1,}/g, '>')
587
+ .replace(/[\s]{2,}/g, ' ');
588
+ const pathPartList = getPathParts(configElement.$.parent || configElement.$.target);
589
+ const doesXmlManifestContainRequiredInfo = (requiredElements, existingElements, pathTarget) => {
590
+ const findElementsToSearchIn = (existingElements, pathTarget) => {
591
+ const parts = [...pathTarget];
592
+ const elementsToSearchNextIn = [];
593
+ for (const existingElement of existingElements) {
594
+ if (existingElement.name === pathTarget[0]) {
595
+ if (existingElement.children) {
596
+ for (const el of existingElement.children) {
597
+ elementsToSearchNextIn.push(el);
598
+ }
599
+ }
600
+ else {
601
+ elementsToSearchNextIn.push(existingElement);
602
+ }
603
+ }
604
+ }
605
+ if (elementsToSearchNextIn.length === 0) {
606
+ return [];
607
+ }
608
+ else {
609
+ parts.splice(0, 1);
610
+ if (parts.length <= 0) {
611
+ return elementsToSearchNextIn;
612
+ }
613
+ else {
614
+ return findElementsToSearchIn(elementsToSearchNextIn, parts);
615
+ }
616
+ }
617
+ };
618
+ const parseXmlToSearchable = (childElementsObj, arrayToAddTo) => {
619
+ for (const childElementKey of Object.keys(childElementsObj)) {
620
+ for (const occurannceOfElement of childElementsObj[childElementKey]) {
621
+ const toAdd = { name: childElementKey };
622
+ if (occurannceOfElement['$']) {
623
+ toAdd.attrs = { ...occurannceOfElement['$'] };
624
+ }
625
+ if (occurannceOfElement['$$']) {
626
+ toAdd.children = [];
627
+ parseXmlToSearchable(occurannceOfElement['$$'], toAdd['children']);
628
+ }
629
+ arrayToAddTo.push(toAdd);
630
+ }
631
+ }
632
+ };
633
+ const doesElementMatch = (requiredElement, existingElement) => {
634
+ var _a;
635
+ if (requiredElement.name !== existingElement.name) {
636
+ return false;
637
+ }
638
+ if ((requiredElement.attrs !== undefined) !== (existingElement.attrs !== undefined)) {
639
+ return false;
640
+ }
641
+ else {
642
+ if (requiredElement.attrs !== undefined) {
643
+ const requiredELementAttrKeys = Object.keys(requiredElement.attrs);
644
+ for (const key of requiredELementAttrKeys) {
645
+ if (!/^[$].{1,}$/.test(requiredElement.attrs[key].trim())) {
646
+ if (requiredElement.attrs[key] !== existingElement.attrs[key]) {
647
+ return false;
648
+ }
649
+ }
650
+ }
651
+ }
652
+ }
653
+ if ((requiredElement.children !== undefined) !== (existingElement.children !== undefined) &&
654
+ ((_a = requiredElement.children) === null || _a === void 0 ? void 0 : _a.length) !== 0) {
655
+ return false;
656
+ }
657
+ else {
658
+ if (requiredElement.children !== undefined) {
659
+ // each req element is in existing element
660
+ for (const requiredElementItem of requiredElement.children) {
661
+ let foundRequiredElement = false;
662
+ for (const existingElementItem of existingElement.children) {
663
+ const foundRequiredElementIn = doesElementMatch(requiredElementItem, existingElementItem);
664
+ if (foundRequiredElementIn) {
665
+ foundRequiredElement = true;
666
+ break;
667
+ }
668
+ }
669
+ if (!foundRequiredElement) {
670
+ return false;
671
+ }
672
+ }
673
+ }
674
+ else {
675
+ if (requiredElement.children === undefined && existingElement.children === undefined) {
676
+ return true;
677
+ }
678
+ else {
679
+ let foundRequiredElement = false;
680
+ for (const existingElementItem of existingElement.children) {
681
+ const foundRequiredElementIn = doesElementMatch(requiredElement, existingElementItem);
682
+ if (foundRequiredElementIn) {
683
+ foundRequiredElement = true;
684
+ break;
685
+ }
686
+ }
687
+ if (!foundRequiredElement) {
688
+ return false;
689
+ }
690
+ }
691
+ }
692
+ }
693
+ return true;
694
+ };
695
+ const parsedExistingElements = [];
696
+ const rootKeyOfExistingElements = Object.keys(existingElements)[0];
697
+ const rootOfExistingElementsToAdd = { name: rootKeyOfExistingElements, children: [] };
698
+ if (existingElements[rootKeyOfExistingElements]['$']) {
699
+ rootOfExistingElementsToAdd.attrs = {
700
+ ...existingElements[rootKeyOfExistingElements]['$'],
701
+ };
702
+ }
703
+ parseXmlToSearchable(existingElements[rootKeyOfExistingElements]['$$'], rootOfExistingElementsToAdd['children']);
704
+ parsedExistingElements.push(rootOfExistingElementsToAdd);
705
+ const parsedRequiredElements = [];
706
+ const rootKeyOfRequiredElements = Object.keys(requiredElements)[0];
707
+ const rootOfRequiredElementsToAdd = { name: rootKeyOfRequiredElements, children: [] };
708
+ if (requiredElements[rootKeyOfRequiredElements]['$']) {
709
+ rootOfRequiredElementsToAdd.attrs = {
710
+ ...requiredElements[rootKeyOfRequiredElements]['$'],
711
+ };
712
+ }
713
+ if (requiredElements[rootKeyOfRequiredElements]['$$'] !== undefined) {
714
+ parseXmlToSearchable(requiredElements[rootKeyOfRequiredElements]['$$'], rootOfRequiredElementsToAdd['children']);
715
+ }
716
+ parsedRequiredElements.push(rootOfRequiredElementsToAdd);
717
+ const elementsToSearch = findElementsToSearchIn(parsedExistingElements, pathTarget);
718
+ for (const requiredElement of parsedRequiredElements) {
719
+ let foundMatch = false;
720
+ for (const existingElement of elementsToSearch) {
721
+ const doesContain = doesElementMatch(requiredElement, existingElement);
722
+ if (doesContain) {
723
+ foundMatch = true;
724
+ break;
725
+ }
726
+ }
727
+ if (!foundMatch) {
728
+ return false;
729
+ }
730
+ }
731
+ return true;
732
+ };
733
+ if (!doesXmlManifestContainRequiredInfo((0, xml_1.parseXML)(requiredManifestContentTrimmed, {
734
+ explicitChildren: true,
735
+ trim: true,
736
+ }), (0, xml_1.parseXML)(manifestContentTrimmed, {
737
+ explicitChildren: true,
738
+ trim: true,
739
+ }), pathPartList)) {
740
+ log_1.logger.warn(`Android Configuration required for ${colors_1.default.strong(p.id)}.\n` +
741
+ `Add the following to AndroidManifest.xml:\n` +
742
+ xmlElement);
743
+ }
744
+ }
745
+ }
746
+ else {
747
+ if (!rootXMLEntries.includes(xmlElement) && !contains(rootXMLEntries, xmlElement, k)) {
748
+ rootXMLEntries.push(xmlElement);
749
+ }
750
+ }
751
+ });
752
+ });
753
+ }
754
+ });
755
+ });
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
759
+ : '';
760
+ let content = `<?xml version='1.0' encoding='utf-8'?>
761
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
762
+ xmlns:amazon="http://schemas.amazon.com/apk/res/android">
763
+ <application ${applicationXMLAttributes.join('\n')} ${cleartextValue}>
764
+ ${applicationXMLEntries.join('\n')}
765
+ </application>
766
+ ${rootXMLEntries.join('\n')}
767
+ </manifest>`;
768
+ content = content.replace(new RegExp('$PACKAGE_NAME'.replace('$', '\\$&'), 'g'), '${applicationId}');
769
+ for (const preference of prefsArray) {
770
+ content = content.replace(new RegExp(('$' + preference.$.name).replace('$', '\\$&'), 'g'), preference.$.default);
771
+ }
772
+ if (await (0, fs_extra_1.pathExists)(manifestPath)) {
773
+ await (0, fs_extra_1.writeFile)(manifestPath, content);
774
+ }
775
+ }
776
+ exports.writeCordovaAndroidManifest = writeCordovaAndroidManifest;
777
+ function getPathParts(path) {
778
+ const rootPath = 'manifest';
779
+ path = path.replace('/*', rootPath);
780
+ const parts = path.split('/').filter((part) => part !== '');
781
+ if (parts.length > 1 || parts.includes(rootPath)) {
782
+ return parts;
783
+ }
784
+ return [rootPath, path];
785
+ }
786
+ function contains(entries, obj, k) {
787
+ const element = (0, xml_1.parseXML)(obj);
788
+ for (const entry of entries) {
789
+ const current = (0, xml_1.parseXML)(entry);
790
+ if (element &&
791
+ current &&
792
+ current[k] &&
793
+ element[k] &&
794
+ current[k].$ &&
795
+ element[k].$ &&
796
+ element[k].$['android:name'] === current[k].$['android:name']) {
797
+ return true;
798
+ }
799
+ }
800
+ return false;
801
+ }