@capacitor-plus/cli 8.3.12 → 8.5.1

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
package/dist/config.js CHANGED
@@ -87,7 +87,7 @@ async function loadExtConfigTS(rootDir, extConfigName, extConfigFilePath) {
87
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
88
  }
89
89
  const ts = require(tsPath); // eslint-disable-line @typescript-eslint/no-var-requires
90
- const extConfigObject = (0, node_1.requireTS)(ts, extConfigFilePath);
90
+ const extConfigObject = (await (0, node_1.requireTS)(ts, extConfigFilePath));
91
91
  const extConfig = extConfigObject.default ? await extConfigObject.default : extConfigObject;
92
92
  return {
93
93
  extConfigType: 'ts',
@@ -511,6 +511,15 @@ export interface CapacitorConfig {
511
511
  packageTraits?: {
512
512
  [pluginId: string]: string[];
513
513
  };
514
+ /**
515
+ * Define options to apply to the package.
516
+ * The key is the plugin ID (e.g. `@capacitor-community/device`)
517
+ *
518
+ * @since 8.4.0
519
+ */
520
+ packageOptions?: {
521
+ [pluginId: string]: PackageOptions;
522
+ };
514
523
  };
515
524
  };
516
525
  };
@@ -546,7 +555,7 @@ export interface CapacitorConfig {
546
555
  * Configure the local scheme on Android.
547
556
  *
548
557
  * Custom schemes on Android are unable to change the URL path as of Webview 117. Changing this value from anything other than `http` or `https` can result in your
549
- * application unable to resolve routing. If you must change this for some reason, consider using a hash-based url strategy, but there are no guarentees that this
558
+ * application unable to resolve routing. If you must change this for some reason, consider using a hash-based url strategy, but there are no guarantees that this
550
559
  * will continue to work long term as allowing non-standard schemes to modify query parameters and url fragments is only allowed for compatibility reasons.
551
560
  * https://ionic.io/blog/capacitor-android-customscheme-issue-with-chrome-117
552
561
  *
@@ -732,3 +741,17 @@ export interface PluginsConfig {
732
741
  animation?: 'FADE' | 'NONE';
733
742
  };
734
743
  }
744
+ export interface PackageOptions {
745
+ /**
746
+ * Create a symlink to the plugin folder instead of pointing to the plugin path.
747
+ * Useful when plugin names conflict.
748
+ */
749
+ symlink?: boolean;
750
+ /**
751
+ * Useful to avoid target name conflicts in dependencies
752
+ * [see](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/modulealiasing/)
753
+ */
754
+ moduleAliases?: {
755
+ [target: string]: string;
756
+ };
757
+ }
@@ -4,6 +4,7 @@ exports.installCocoaPodsPlugins = exports.updateIOS = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const fs_extra_1 = require("fs-extra");
6
6
  const path_1 = require("path");
7
+ const semver_1 = require("semver");
7
8
  const colors_1 = tslib_1.__importDefault(require("../colors"));
8
9
  const common_1 = require("../common");
9
10
  const cordova_1 = require("../cordova");
@@ -45,6 +46,37 @@ async function updatePluginFiles(config, plugins, deployment) {
45
46
  await generateCordovaPackageFiles(cordovaPlugins, config);
46
47
  const validSPMPackages = await (0, spm_1.checkPluginsForPackageSwift)(config, plugins);
47
48
  await (0, spm_1.generatePackageFile)(config, validSPMPackages.concat(cordovaPlugins));
49
+ if (validSPMPackages.length > 0) {
50
+ let platformVersion;
51
+ try {
52
+ platformVersion = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name);
53
+ }
54
+ catch (err) {
55
+ log_1.logger.warn(`Skipping plugin Package.swift Capacitor version patching: ${err}`);
56
+ }
57
+ if (platformVersion) {
58
+ const resolvedPlatformVersion = platformVersion;
59
+ await Promise.all(validSPMPackages.map(async (plugin) => {
60
+ var _a;
61
+ const packageSwiftPath = (0, path_1.join)(plugin.rootPath, 'Package.swift');
62
+ let content = await (0, fs_extra_1.readFile)(packageSwiftPath, { encoding: 'utf-8' });
63
+ const regex = new RegExp('url:\\s*"https://github.com/ionic-team/capacitor-swift-pm\\.git",\\s*(?:from|exact):\\s*"([^"]+)"');
64
+ const version = (_a = content.match(regex)) === null || _a === void 0 ? void 0 : _a[1];
65
+ if (!version || !(0, semver_1.valid)(version)) {
66
+ log_1.logger.warn(`${plugin.id}: skipping Package.swift version check for invalid version "${version !== null && version !== void 0 ? version : ''}"`);
67
+ return;
68
+ }
69
+ const majorCapVersion = (0, semver_1.major)(resolvedPlatformVersion);
70
+ if ((0, semver_1.major)(version) != majorCapVersion) {
71
+ const preCapVersion = (0, semver_1.prerelease)(resolvedPlatformVersion);
72
+ const forceVersion = preCapVersion ? resolvedPlatformVersion : `${majorCapVersion}.0.0`;
73
+ content = (0, migrate_1.setAllStringIn)(content, `url: "https://github.com/ionic-team/capacitor-swift-pm.git",`, `)`, ` from: "${forceVersion}"`);
74
+ await (0, fs_extra_1.writeFile)(packageSwiftPath, content);
75
+ log_1.logger.warn(`${plugin.id} is built for Capacitor ${(0, semver_1.major)(version)}, it might cause issues`);
76
+ }
77
+ }));
78
+ }
79
+ }
48
80
  }
49
81
  else {
50
82
  await generateCordovaPodspecs(cordovaPlugins, config);
@@ -578,6 +610,9 @@ async function copyPluginsNativeFiles(config, cordovaPlugins) {
578
610
  }
579
611
  async function removePluginsNativeFiles(config) {
580
612
  await (0, fs_extra_1.remove)(config.ios.cordovaPluginsDirAbs);
613
+ if ((await config.ios.packageManager) === 'SPM') {
614
+ await (0, fs_extra_1.remove)((0, path_1.join)(config.ios.nativeProjectDirAbs, 'CapApp-SPM', 'symlinks'));
615
+ }
581
616
  await (0, template_1.extractTemplate)(config.cli.assets.ios.cordovaPluginsTemplateArchiveAbs, config.ios.cordovaPluginsDirAbs);
582
617
  }
583
618
  function filterResources(plugin) {
package/dist/ipc.js CHANGED
@@ -36,21 +36,26 @@ async function receive(msg) {
36
36
  const { data } = msg;
37
37
  // This request is only made if telemetry is on.
38
38
  const req = (0, https_1.request)({
39
- hostname: 'api.ionicjs.com',
39
+ hostname: 'metrics-capacitor.outsystems.com',
40
40
  port: 443,
41
- path: '/events/metrics',
41
+ path: '/metrics',
42
42
  method: 'POST',
43
+ timeout: 5000,
43
44
  headers: {
44
45
  'Content-Type': 'application/json',
45
46
  },
46
47
  }, (response) => {
47
48
  debug('Sent %O metric to events service (status: %O)', data.name, response.statusCode);
48
- if (response.statusCode !== 204) {
49
+ if (response.statusCode !== 202) {
49
50
  response.on('data', (chunk) => {
50
51
  debug('Bad response from events service. Request body: %O', chunk.toString());
51
52
  });
52
53
  }
53
54
  });
55
+ req.on('timeout', () => req.destroy());
56
+ req.on('error', (err) => {
57
+ debug('Failed to send metric to events service: %O', err);
58
+ });
54
59
  const body = {
55
60
  metrics: [data],
56
61
  sent_at: now,
@@ -0,0 +1,349 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.__testables = exports.migrateToUIScene = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const path_1 = require("path");
6
+ const common_1 = require("../common");
7
+ const log_1 = require("../log");
8
+ const fs_1 = require("../util/fs");
9
+ const spm_1 = require("../util/spm");
10
+ const template_1 = require("../util/template");
11
+ const xcode_1 = require("../util/xcode");
12
+ async function migrateToUIScene(config) {
13
+ const signals = readDetectionSignals(config);
14
+ const state = classify(signals);
15
+ switch (state) {
16
+ case 'already-migrated':
17
+ log_1.logger.info('UIScene migration: project already migrated, skipping.');
18
+ return;
19
+ case 'partial':
20
+ log_1.logger.warn(`UIScene migration: project is in a partial state (${describeSignals(signals)}). ` +
21
+ `Skipping automated migration — finish the migration by hand or reset to a clean 8.4 state first.`);
22
+ return;
23
+ case 'eligible':
24
+ break;
25
+ }
26
+ const assets = await loadTemplateAssets(config);
27
+ if (!assets) {
28
+ log_1.logger.error('UIScene migration: could not read shipped iOS template assets; skipping.');
29
+ return;
30
+ }
31
+ await (0, common_1.runTask)('Adding UIApplicationSceneManifest to Info.plist.', () => (0, spm_1.addSceneManifestIfNeeded)(config));
32
+ await (0, common_1.runTask)('Writing SceneDelegate.swift.', async () => {
33
+ const { written } = writeSceneDelegate(config, assets.sceneDelegate);
34
+ if (!written) {
35
+ log_1.logger.warn('SceneDelegate.swift already exists, skipping.');
36
+ }
37
+ });
38
+ await (0, common_1.runTask)('Patching AppDelegate.swift with configurationForConnecting.', async () => {
39
+ const { patched, reason } = patchAppDelegate(config, assets.configurationForConnectingSnippet);
40
+ if (!patched && reason) {
41
+ log_1.logger.warn(`AppDelegate.swift not patched: ${reason}`);
42
+ }
43
+ });
44
+ await (0, common_1.runTask)('Registering SceneDelegate.swift with the Xcode App target.', async () => {
45
+ var _a;
46
+ const pbxprojPath = (0, path_1.join)(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj');
47
+ try {
48
+ const { added } = (0, xcode_1.addSwiftFileToAppTarget)(pbxprojPath, 'App', 'SceneDelegate.swift');
49
+ if (!added) {
50
+ log_1.logger.warn('SceneDelegate.swift is already registered in the App target, skipping.');
51
+ }
52
+ }
53
+ catch (err) {
54
+ log_1.logger.warn(`Could not register SceneDelegate.swift automatically: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}. ` +
55
+ 'Add SceneDelegate.swift to the App target in Xcode manually.');
56
+ }
57
+ });
58
+ await scanAndWarn(config);
59
+ printNextSteps();
60
+ }
61
+ exports.migrateToUIScene = migrateToUIScene;
62
+ async function scanAndWarn(config) {
63
+ const findings = [];
64
+ const swiftFiles = await (0, fs_1.readdirp)(config.ios.platformDirAbs, {
65
+ filter: (item) => {
66
+ if (!item.stats.isFile())
67
+ return false;
68
+ if (!item.path.endsWith('.swift'))
69
+ return false;
70
+ const p = item.path;
71
+ return (!p.includes(`${path_1.sep}Pods${path_1.sep}`) &&
72
+ !p.includes(`${path_1.sep}build${path_1.sep}`) &&
73
+ !p.includes(`${path_1.sep}DerivedData${path_1.sep}`) &&
74
+ !p.includes(`${path_1.sep}.build${path_1.sep}`));
75
+ },
76
+ });
77
+ const tokenPatterns = [
78
+ { token: /UIApplication\.shared\.applicationState/, label: 'UIApplication.shared.applicationState' },
79
+ { token: /\btmpWindow\b/, label: 'tmpWindow' },
80
+ { token: /\bTmpViewController\b/, label: 'TmpViewController' },
81
+ ];
82
+ for (const filePath of swiftFiles) {
83
+ const source = (0, fs_extra_1.readFileSync)(filePath, 'utf-8');
84
+ source.split('\n').forEach((line, idx) => {
85
+ for (const { token, label } of tokenPatterns) {
86
+ if (token.test(line)) {
87
+ findings.push(`${filePath}:${idx + 1}: uses ${label}`);
88
+ }
89
+ }
90
+ });
91
+ }
92
+ const appDelegatePath = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'AppDelegate.swift');
93
+ if ((0, fs_extra_1.existsSync)(appDelegatePath)) {
94
+ const source = (0, fs_extra_1.readFileSync)(appDelegatePath, 'utf-8');
95
+ if (hasCustomDelegateBody(source, /func application\([^)]*\bopen url:/)) {
96
+ findings.push(`${appDelegatePath}: custom application(_:open:) body — review for UIScene compatibility`);
97
+ }
98
+ if (hasCustomDelegateBody(source, /func application\([^)]*\bcontinue userActivity:/)) {
99
+ findings.push(`${appDelegatePath}: custom application(_:continue:) body — review for UIScene compatibility`);
100
+ }
101
+ }
102
+ if (findings.length === 0)
103
+ return;
104
+ log_1.logger.warn('UIScene scan found patterns that may need manual review:');
105
+ for (const finding of findings) {
106
+ log_1.logger.warn(` ${finding}`);
107
+ }
108
+ }
109
+ function findMatchingBrace(source, openIdx) {
110
+ let depth = 1;
111
+ let i = openIdx + 1;
112
+ let inLineComment = false;
113
+ let blockCommentDepth = 0;
114
+ let inString = null;
115
+ let stringHashes = 0;
116
+ while (i < source.length && depth > 0) {
117
+ const ch = source[i];
118
+ const next = source[i + 1];
119
+ if (inLineComment) {
120
+ if (ch === '\n')
121
+ inLineComment = false;
122
+ i++;
123
+ continue;
124
+ }
125
+ if (blockCommentDepth > 0) {
126
+ if (ch === '*' && next === '/') {
127
+ blockCommentDepth--;
128
+ i += 2;
129
+ continue;
130
+ }
131
+ if (ch === '/' && next === '*') {
132
+ blockCommentDepth++;
133
+ i += 2;
134
+ continue;
135
+ }
136
+ i++;
137
+ continue;
138
+ }
139
+ if (inString === '"') {
140
+ if (stringHashes === 0 && ch === '\\') {
141
+ i += 2;
142
+ continue;
143
+ }
144
+ if (ch === '"') {
145
+ let closingHashes = 0;
146
+ while (source[i + 1 + closingHashes] === '#') {
147
+ closingHashes++;
148
+ }
149
+ if (closingHashes === stringHashes) {
150
+ i += 1 + closingHashes;
151
+ inString = null;
152
+ stringHashes = 0;
153
+ continue;
154
+ }
155
+ }
156
+ i++;
157
+ continue;
158
+ }
159
+ if (inString === '"""') {
160
+ if (ch === '"' && source[i + 1] === '"' && source[i + 2] === '"') {
161
+ let closingHashes = 0;
162
+ while (source[i + 3 + closingHashes] === '#') {
163
+ closingHashes++;
164
+ }
165
+ if (closingHashes === stringHashes) {
166
+ i += 3 + closingHashes;
167
+ inString = null;
168
+ stringHashes = 0;
169
+ continue;
170
+ }
171
+ }
172
+ i++;
173
+ continue;
174
+ }
175
+ if (ch === '/' && next === '/') {
176
+ inLineComment = true;
177
+ i += 2;
178
+ continue;
179
+ }
180
+ if (ch === '/' && next === '*') {
181
+ blockCommentDepth++;
182
+ i += 2;
183
+ continue;
184
+ }
185
+ if (ch === '#' || ch === '"') {
186
+ let hashes = 0;
187
+ while (source[i + hashes] === '#') {
188
+ hashes++;
189
+ }
190
+ const quoteIdx = i + hashes;
191
+ if (source[quoteIdx] === '"') {
192
+ if (source[quoteIdx + 1] === '"' && source[quoteIdx + 2] === '"') {
193
+ inString = '"""';
194
+ stringHashes = hashes;
195
+ i = quoteIdx + 3;
196
+ continue;
197
+ }
198
+ inString = '"';
199
+ stringHashes = hashes;
200
+ i = quoteIdx + 1;
201
+ continue;
202
+ }
203
+ }
204
+ if (ch === '{')
205
+ depth++;
206
+ else if (ch === '}')
207
+ depth--;
208
+ i++;
209
+ }
210
+ return depth === 0 ? i - 1 : null;
211
+ }
212
+ function hasCustomDelegateBody(source, sigRegex) {
213
+ const match = source.match(sigRegex);
214
+ if (!match || match.index === undefined)
215
+ return false;
216
+ const openIdx = source.indexOf('{', match.index);
217
+ if (openIdx === -1)
218
+ return false;
219
+ const closeIdx = findMatchingBrace(source, openIdx);
220
+ if (closeIdx === null)
221
+ return false;
222
+ const body = source.slice(openIdx + 1, closeIdx);
223
+ const codeLines = body
224
+ .split('\n')
225
+ .map((l) => l.trim())
226
+ .filter((l) => l.length > 0 && !l.startsWith('//'));
227
+ if (codeLines.length === 0)
228
+ return false;
229
+ return codeLines.some((l) => !l.includes('ApplicationDelegateProxy.shared'));
230
+ }
231
+ function printNextSteps() {
232
+ log_1.logger.info('');
233
+ log_1.logger.info('UIScene migration next steps:');
234
+ log_1.logger.info(' • Review any warnings above for legacy API usage or custom AppDelegate URL/activity handlers.');
235
+ log_1.logger.info(' • Full guide: https://capacitorjs.com/docs/updating/8-5');
236
+ }
237
+ async function loadTemplateAssets(config) {
238
+ const packageManager = await config.ios.packageManager;
239
+ const archiveName = packageManager === 'SPM' ? 'ios-spm-template.tar.gz' : 'ios-pods-template.tar.gz';
240
+ const archivePath = (0, path_1.join)(config.cli.assetsDirAbs, archiveName);
241
+ const tempDir = (0, path_1.join)(config.cli.assetsDirAbs, 'tempUISceneTemplate');
242
+ try {
243
+ await (0, template_1.extractTemplate)(archivePath, tempDir);
244
+ const sceneDelegatePath = (0, path_1.join)(tempDir, 'App', 'App', 'SceneDelegate.swift');
245
+ const appDelegatePath = (0, path_1.join)(tempDir, 'App', 'App', 'AppDelegate.swift');
246
+ if (!(0, fs_extra_1.existsSync)(sceneDelegatePath) || !(0, fs_extra_1.existsSync)(appDelegatePath)) {
247
+ return null;
248
+ }
249
+ const sceneDelegate = (0, fs_extra_1.readFileSync)(sceneDelegatePath, 'utf-8');
250
+ const appDelegateSource = (0, fs_extra_1.readFileSync)(appDelegatePath, 'utf-8');
251
+ const configurationForConnectingSnippet = extractConfigurationForConnecting(appDelegateSource);
252
+ if (!configurationForConnectingSnippet) {
253
+ return null;
254
+ }
255
+ return { sceneDelegate, configurationForConnectingSnippet };
256
+ }
257
+ finally {
258
+ (0, fs_1.deleteFolderRecursive)(tempDir);
259
+ }
260
+ }
261
+ function writeSceneDelegate(config, contents) {
262
+ const path = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'SceneDelegate.swift');
263
+ if ((0, fs_extra_1.existsSync)(path)) {
264
+ return { written: false };
265
+ }
266
+ (0, fs_extra_1.writeFileSync)(path, contents);
267
+ return { written: true };
268
+ }
269
+ function patchAppDelegate(config, snippet) {
270
+ const path = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'AppDelegate.swift');
271
+ if (!(0, fs_extra_1.existsSync)(path)) {
272
+ return { patched: false, reason: 'AppDelegate.swift not found.' };
273
+ }
274
+ const source = (0, fs_extra_1.readFileSync)(path, 'utf-8');
275
+ if (source.includes('UISceneConfiguration(name:')) {
276
+ return { patched: false, reason: 'configurationForConnecting already present.' };
277
+ }
278
+ const patched = insertBeforeAppDelegateClassEnd(source, snippet);
279
+ if (!patched) {
280
+ return { patched: false, reason: 'could not locate AppDelegate class body.' };
281
+ }
282
+ (0, fs_extra_1.writeFileSync)(path, patched);
283
+ return { patched: true };
284
+ }
285
+ function extractConfigurationForConnecting(appDelegateSource) {
286
+ const sigRegex = /^ {4}func application\(_ application: UIApplication,\n {21}configurationForConnecting\b/m;
287
+ const sigMatch = appDelegateSource.match(sigRegex);
288
+ if (!sigMatch || sigMatch.index === undefined) {
289
+ return null;
290
+ }
291
+ const openIdx = appDelegateSource.indexOf('{', sigMatch.index);
292
+ if (openIdx === -1) {
293
+ return null;
294
+ }
295
+ const closeIdx = findMatchingBrace(appDelegateSource, openIdx);
296
+ if (closeIdx === null) {
297
+ return null;
298
+ }
299
+ return '\n' + appDelegateSource.slice(sigMatch.index, closeIdx + 1) + '\n';
300
+ }
301
+ function insertBeforeAppDelegateClassEnd(source, snippet) {
302
+ const classDeclRegex = /\bclass\s+AppDelegate\b[^{]*\{/;
303
+ const match = source.match(classDeclRegex);
304
+ if (!match || match.index === undefined) {
305
+ return null;
306
+ }
307
+ const openIdx = source.indexOf('{', match.index);
308
+ const closeIdx = findMatchingBrace(source, openIdx);
309
+ if (closeIdx === null) {
310
+ return null;
311
+ }
312
+ return source.slice(0, closeIdx) + snippet + source.slice(closeIdx);
313
+ }
314
+ function readDetectionSignals(config) {
315
+ const sceneDelegatePath = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'SceneDelegate.swift');
316
+ const appDelegatePath = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'AppDelegate.swift');
317
+ return {
318
+ hasManifest: (0, spm_1.hasSceneManifest)(config),
319
+ hasSceneDelegate: (0, fs_extra_1.existsSync)(sceneDelegatePath),
320
+ hasConfigurationForConnecting: (0, fs_extra_1.existsSync)(appDelegatePath) && (0, fs_extra_1.readFileSync)(appDelegatePath, 'utf-8').includes('UISceneConfiguration(name:'),
321
+ };
322
+ }
323
+ function classify(signals) {
324
+ const { hasManifest, hasSceneDelegate, hasConfigurationForConnecting } = signals;
325
+ const trueCount = [hasManifest, hasSceneDelegate, hasConfigurationForConnecting].filter(Boolean).length;
326
+ if (trueCount === 0)
327
+ return 'eligible';
328
+ if (trueCount === 3)
329
+ return 'already-migrated';
330
+ return 'partial';
331
+ }
332
+ function describeSignals({ hasManifest, hasSceneDelegate, hasConfigurationForConnecting, }) {
333
+ const present = [];
334
+ const missing = [];
335
+ (hasManifest ? present : missing).push('UIApplicationSceneManifest');
336
+ (hasSceneDelegate ? present : missing).push('SceneDelegate.swift');
337
+ (hasConfigurationForConnecting ? present : missing).push('AppDelegate.configurationForConnecting');
338
+ return `present: [${present.join(', ')}]; missing: [${missing.join(', ')}]`;
339
+ }
340
+ // Exported for tests.
341
+ exports.__testables = {
342
+ classify,
343
+ describeSignals,
344
+ findMatchingBrace,
345
+ insertBeforeAppDelegateClassEnd,
346
+ extractConfigurationForConnecting,
347
+ hasCustomDelegateBody,
348
+ scanAndWarn,
349
+ };
@@ -14,6 +14,7 @@ const log_1 = require("../log");
14
14
  const fs_1 = require("../util/fs");
15
15
  const subprocess_1 = require("../util/subprocess");
16
16
  const template_1 = require("../util/template");
17
+ const migrate_uiscene_1 = require("./migrate-uiscene");
17
18
  // eslint-disable-next-line prefer-const
18
19
  let allDependencies = {};
19
20
  const libs = [
@@ -171,6 +172,7 @@ async function migrateCommand(config, noprompt, packagemanager) {
171
172
  else {
172
173
  log_1.logger.warn('Skipped updating deployment target');
173
174
  }
175
+ await (0, migrate_uiscene_1.migrateToUIScene)(config);
174
176
  }
175
177
  if (!installFailed) {
176
178
  await (0, common_1.runTask)(`Running cap sync.`, () => {
@@ -371,6 +373,10 @@ async function writeBreakingChanges() {
371
373
  if (broken.length > 0) {
372
374
  log_1.logger.info(`IMPORTANT: Review https://capacitorjs.com/docs/next/updating/8-0#plugins for breaking changes in these plugins that you use: ${broken.join(', ')}.`);
373
375
  }
376
+ if (allDependencies['@capacitor/ios'] || allDependencies['@capacitor-plus/ios']) {
377
+ log_1.logger.info('IMPORTANT: Capacitor 8.5 adopts UIScene on iOS. ' +
378
+ 'See https://capacitorjs.com/docs/updating/8-5 for the full 8.4 → 8.5 migration guide.');
379
+ }
374
380
  }
375
381
  async function getAndroidVariablesAndClasspaths(config) {
376
382
  const tempAndroidTemplateFolder = (0, path_1.join)(config.cli.assetsDirAbs, 'tempAndroidTemplate');
package/dist/tasks/run.js CHANGED
@@ -59,15 +59,18 @@ async function runCommand(config, selectedPlatformName, options) {
59
59
  }
60
60
  return;
61
61
  }
62
+ let cordovaPlugins;
63
+ let liveReloadManifestUpdated = false;
62
64
  try {
65
+ cordovaPlugins = await (0, cordova_1.getCordovaPlugins)(config, platformName);
63
66
  if (options.sync) {
64
67
  await (0, sync_1.sync)(config, platformName, false, true);
65
68
  }
66
- const cordovaPlugins = await (0, cordova_1.getCordovaPlugins)(config, platformName);
67
69
  if (options.liveReload) {
68
70
  await livereload_1.CapLiveReloadHelper.editCapConfigForLiveReload(config, platformName, options);
69
71
  if (platformName === config.android.name) {
70
- await await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platformName, true);
72
+ await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platformName, true);
73
+ liveReloadManifestUpdated = true;
71
74
  }
72
75
  }
73
76
  await run(config, platformName, options);
@@ -75,7 +78,7 @@ async function runCommand(config, selectedPlatformName, options) {
75
78
  new Promise((resolve) => process.on('SIGINT', resolve))
76
79
  .then(async () => {
77
80
  await livereload_1.CapLiveReloadHelper.revertCapConfigForLiveReload();
78
- if (platformName === config.android.name) {
81
+ if (liveReloadManifestUpdated && platformName === config.android.name && cordovaPlugins) {
79
82
  await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platformName, false);
80
83
  }
81
84
  })
@@ -85,6 +88,12 @@ async function runCommand(config, selectedPlatformName, options) {
85
88
  }
86
89
  }
87
90
  catch (e) {
91
+ if (options.liveReload) {
92
+ await livereload_1.CapLiveReloadHelper.revertCapConfigForLiveReload();
93
+ if (liveReloadManifestUpdated && platformName === config.android.name && cordovaPlugins) {
94
+ await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platformName, false);
95
+ }
96
+ }
88
97
  if (!(0, errors_1.isFatal)(e)) {
89
98
  (0, errors_1.fatal)((_c = e.stack) !== null && _c !== void 0 ? _c : e);
90
99
  }
package/dist/telemetry.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sendMetric = exports.telemetryAction = void 0;
3
+ exports.getIOSPackageManager = exports.sendMetric = exports.telemetryAction = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const commander_1 = require("commander");
6
6
  const debug_1 = tslib_1.__importDefault(require("debug"));
7
+ const fs_extra_1 = require("fs-extra");
7
8
  const colors_1 = tslib_1.__importDefault(require("./colors"));
8
9
  const ipc_1 = require("./ipc");
9
10
  const log_1 = require("./log");
@@ -51,8 +52,10 @@ function telemetryAction(config, action) {
51
52
  error: error ? (error.message ? error.message : String(error)) : null,
52
53
  node_version: process.version,
53
54
  os: config.cli.os,
55
+ ios_package_manager: await getIOSPackageManager(config),
54
56
  ...Object.fromEntries(versions),
55
57
  };
58
+ debug('metric payload: %O', data);
56
59
  if ((0, term_1.isInteractive)()) {
57
60
  let sysconfig = await (0, sysconfig_1.readConfig)();
58
61
  if (!error && typeof sysconfig.telemetry === 'undefined') {
@@ -88,6 +91,24 @@ async function sendMetric(sysconfig, name, data) {
88
91
  }
89
92
  }
90
93
  exports.sendMetric = sendMetric;
94
+ /**
95
+ * Resolve the iOS dependency manager for telemetry. Returns 'unknown' for
96
+ * non-iOS projects or when detection throws, so callers never have to handle
97
+ * errors from this signal.
98
+ */
99
+ async function getIOSPackageManager(config) {
100
+ try {
101
+ if (!(await (0, fs_extra_1.pathExists)(config.ios.platformDirAbs))) {
102
+ return 'unknown';
103
+ }
104
+ return await config.ios.packageManager;
105
+ }
106
+ catch (e) {
107
+ debug('Could not resolve iOS package manager for telemetry: %O', e);
108
+ return 'unknown';
109
+ }
110
+ }
111
+ exports.getIOSPackageManager = getIOSPackageManager;
91
112
  /**
92
113
  * Get a unique anonymous identifier for this app.
93
114
  */
package/dist/util/node.js CHANGED
@@ -4,11 +4,28 @@ exports.resolveNode = exports.requireTS = void 0;
4
4
  const fs_1 = require("fs");
5
5
  const fs_extra_1 = require("fs-extra");
6
6
  const path_1 = require("path");
7
+ const url_1 = require("url");
8
+ /**
9
+ * TypeScript 7 dropped the classic compiler API (transpileModule, ModuleKind, etc.) from its
10
+ * default export -- `require('typescript')` now only exposes `version`/`versionMajorMinor`.
11
+ * Detect that case so we can fall back to a loading strategy that doesn't depend on it.
12
+ *
13
+ * @see https://github.com/ionic-team/capacitor/issues/8531
14
+ */
15
+ function hasClassicCompilerAPI(ts) {
16
+ return typeof ts.transpileModule === 'function';
17
+ }
18
+ /**
19
+ * A plain `import()` here gets downleveled to a `require()` call by tsc when compiling to
20
+ * CommonJS (our build target), which defeats the purpose -- we specifically need the real ESM
21
+ * loader so Node's native TypeScript stripping kicks in. Constructing the import from a string
22
+ * keeps tsc from touching it.
23
+ */
24
+ const dynamicImport = new Function('specifier', 'return import(specifier)');
7
25
  /**
8
26
  * @see https://github.com/ionic-team/stencil/blob/HEAD/src/compiler/sys/node-require.ts
9
27
  */
10
- const requireTS = (ts, p) => {
11
- const id = (0, path_1.resolve)(p);
28
+ function loadWithClassicCompiler(ts, id) {
12
29
  delete require.cache[id];
13
30
  require.extensions['.ts'] = (module, fileName) => {
14
31
  var _a;
@@ -37,6 +54,49 @@ const requireTS = (ts, p) => {
37
54
  const m = require(id); // eslint-disable-line @typescript-eslint/no-var-requires
38
55
  delete require.extensions['.ts'];
39
56
  return m;
57
+ }
58
+ function loadWithCliBundledCompiler(id) {
59
+ const cliRoot = (0, path_1.resolve)(__dirname, '..', '..');
60
+ let cliTsPath;
61
+ try {
62
+ cliTsPath = require.resolve('typescript', { paths: [cliRoot] });
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ const cliTs = require(cliTsPath); // eslint-disable-line @typescript-eslint/no-var-requires
68
+ if (!hasClassicCompilerAPI(cliTs)) {
69
+ return null;
70
+ }
71
+ return loadWithClassicCompiler(cliTs, id);
72
+ }
73
+ const requireTS = async (ts, p) => {
74
+ const id = (0, path_1.resolve)(p);
75
+ if (!hasClassicCompilerAPI(ts)) {
76
+ // Node has its own built-in TypeScript syntax stripping (stable since Node 23.6, and
77
+ // available behind --experimental-strip-types since Node 22.6), so we can load the file
78
+ // directly via the native ESM loader instead of transpiling it ourselves.
79
+ try {
80
+ return await dynamicImport((0, url_1.pathToFileURL)(id).href);
81
+ }
82
+ catch (e) {
83
+ if ((e === null || e === void 0 ? void 0 : e.code) === 'ERR_UNKNOWN_FILE_EXTENSION') {
84
+ throw new Error(`Your installed version of TypeScript (${ts.version}) no longer provides the compiler API Capacitor previously used to load .ts config files, ` +
85
+ `and your Node.js runtime (${process.version}) doesn't support loading them natively either.\n` +
86
+ 'Upgrade to Node.js 22.6+ (running with --experimental-strip-types), or Node.js 23.6+, to continue using capacitor.config.ts.');
87
+ }
88
+ if ((e === null || e === void 0 ? void 0 : e.code) === 'ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX') {
89
+ const compiled = loadWithCliBundledCompiler(id);
90
+ if (compiled !== null) {
91
+ return compiled;
92
+ }
93
+ throw new Error(`Your capacitor.config.ts uses TypeScript syntax that cannot be loaded with Node's native type stripping (${e.message}).\n` +
94
+ 'Use erasable TypeScript syntax in capacitor.config.ts, or install a TypeScript version that still exposes the compiler API.');
95
+ }
96
+ throw e;
97
+ }
98
+ }
99
+ return loadWithClassicCompiler(ts, id);
40
100
  };
41
101
  exports.requireTS = requireTS;
42
102
  function resolveNode(root, ...pathSegments) {
package/dist/util/spm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.checkPackageTraitsRequirements = exports.checkSwiftToolsVersion = exports.addInfoPlistDebugIfNeeded = exports.runCocoapodsDeintegrate = exports.generatePackageText = exports.removeCocoapodsFiles = exports.extractSPMPackageDirectory = exports.checkPluginsForPackageSwift = exports.generatePackageFile = exports.findPackageSwiftFile = exports.checkPackageManager = void 0;
3
+ exports.checkPackageTraitsRequirements = exports.checkSwiftToolsVersion = exports.addSceneManifestIfNeeded = exports.hasSceneManifest = exports.addInfoPlistDebugIfNeeded = exports.runCocoapodsDeintegrate = exports.generatePackageText = exports.removeCocoapodsFiles = exports.extractSPMPackageDirectory = exports.checkPluginsForPackageSwift = exports.generatePackageFile = exports.findPackageSwiftFile = exports.checkPackageManager = void 0;
4
4
  const fs_extra_1 = require("fs-extra");
5
5
  const os_1 = require("os");
6
6
  const path_1 = require("path");
@@ -11,6 +11,7 @@ const errors_1 = require("../errors");
11
11
  const common_2 = require("../ios/common");
12
12
  const log_1 = require("../log");
13
13
  const plugin_1 = require("../plugin");
14
+ const fs_1 = require("../util/fs");
14
15
  const subprocess_1 = require("../util/subprocess");
15
16
  /**
16
17
  * @deprecated use config.ios.packageManager
@@ -84,11 +85,12 @@ async function removeCocoapodsFiles(config) {
84
85
  }
85
86
  exports.removeCocoapodsFiles = removeCocoapodsFiles;
86
87
  async function generatePackageText(config, plugins) {
87
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
88
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
88
89
  const iosPlatformVersion = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name);
89
90
  const iosVersion = (0, common_2.getMajorMinoriOSVersion)(config);
90
91
  const packageTraits = (_d = (_c = (_b = (_a = config.app.extConfig.experimental) === null || _a === void 0 ? void 0 : _a.ios) === null || _b === void 0 ? void 0 : _b.spm) === null || _c === void 0 ? void 0 : _c.packageTraits) !== null && _d !== void 0 ? _d : {};
91
- const swiftToolsVersion = (_h = (_g = (_f = (_e = config.app.extConfig.experimental) === null || _e === void 0 ? void 0 : _e.ios) === null || _f === void 0 ? void 0 : _f.spm) === null || _g === void 0 ? void 0 : _g.swiftToolsVersion) !== null && _h !== void 0 ? _h : '5.9';
92
+ const packageOptions = (_h = (_g = (_f = (_e = config.app.extConfig.experimental) === null || _e === void 0 ? void 0 : _e.ios) === null || _f === void 0 ? void 0 : _f.spm) === null || _g === void 0 ? void 0 : _g.packageOptions) !== null && _h !== void 0 ? _h : {};
93
+ const swiftToolsVersion = (_m = (_l = (_k = (_j = config.app.extConfig.experimental) === null || _j === void 0 ? void 0 : _j.ios) === null || _k === void 0 ? void 0 : _k.spm) === null || _l === void 0 ? void 0 : _l.swiftToolsVersion) !== null && _m !== void 0 ? _m : '5.9';
92
94
  let packageSwiftText = `// swift-tools-version: ${swiftToolsVersion}
93
95
  import PackageDescription
94
96
 
@@ -106,8 +108,8 @@ let package = Package(
106
108
  for (const plugin of plugins) {
107
109
  if ((0, plugin_1.getPluginType)(plugin, config.ios.name) === 1 /* PluginType.Cordova */) {
108
110
  const platformTag = (0, plugin_1.getPluginPlatform)(plugin, config.ios.name);
109
- if ((_j = platformTag.$) === null || _j === void 0 ? void 0 : _j.package) {
110
- const relPath = (0, path_1.relative)(config.ios.nativeXcodeProjDirAbs, plugin.rootPath);
111
+ if ((_o = platformTag.$) === null || _o === void 0 ? void 0 : _o.package) {
112
+ const relPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(config.ios.nativeXcodeProjDirAbs, plugin.rootPath));
111
113
  packageSwiftText += `,\n .package(name: "${plugin.id}", path: "${relPath}")`;
112
114
  }
113
115
  else {
@@ -120,7 +122,13 @@ let package = Package(
120
122
  }
121
123
  }
122
124
  else {
123
- const relPath = (0, path_1.relative)(config.ios.nativeXcodeProjDirAbs, plugin.rootPath);
125
+ const options = packageOptions[plugin.id];
126
+ const symlink = options === null || options === void 0 ? void 0 : options.symlink;
127
+ const symlinkFolder = (0, path_1.join)('symlinks', plugin.name);
128
+ const relPath = (0, fs_1.convertToUnixPath)(symlink ? symlinkFolder : (0, path_1.relative)(config.ios.nativeXcodeProjDirAbs, plugin.rootPath));
129
+ if (symlink) {
130
+ await (0, fs_extra_1.ensureSymlink)(plugin.rootPath, (0, path_1.resolve)(config.ios.nativeProjectDirAbs, 'CapApp-SPM', symlinkFolder));
131
+ }
124
132
  const traits = packageTraits[plugin.id];
125
133
  const traitsSuffix = (traits === null || traits === void 0 ? void 0 : traits.length)
126
134
  ? `, traits: [${traits
@@ -130,7 +138,7 @@ let package = Package(
130
138
  })
131
139
  .join(', ')}]`
132
140
  : '';
133
- packageSwiftText += `,\n .package(name: "${(_k = plugin.ios) === null || _k === void 0 ? void 0 : _k.name}", path: "${relPath}"${traitsSuffix})`;
141
+ packageSwiftText += `,\n .package(name: "${(_p = plugin.ios) === null || _p === void 0 ? void 0 : _p.name}", path: "${relPath}"${traitsSuffix})`;
134
142
  }
135
143
  }
136
144
  packageSwiftText += `
@@ -142,11 +150,19 @@ let package = Package(
142
150
  .product(name: "Capacitor", package: "capacitor-swift-pm"),
143
151
  .product(name: "Cordova", package: "capacitor-swift-pm")`;
144
152
  for (const plugin of plugins) {
145
- let pluginText = `,\n .product(name: "${(_l = plugin.ios) === null || _l === void 0 ? void 0 : _l.name}", package: "${(_m = plugin.ios) === null || _m === void 0 ? void 0 : _m.name}")`;
153
+ const aliases = Object.entries((_r = (_q = packageOptions[plugin.id]) === null || _q === void 0 ? void 0 : _q.moduleAliases) !== null && _r !== void 0 ? _r : {});
154
+ const aliasText = (aliases === null || aliases === void 0 ? void 0 : aliases.length)
155
+ ? `, moduleAliases: [${aliases
156
+ .map(([target, replacement]) => {
157
+ return `"${target}": "${replacement}"`;
158
+ })
159
+ .join(', ')}]`
160
+ : '';
161
+ let pluginText = `,\n .product(name: "${(_s = plugin.ios) === null || _s === void 0 ? void 0 : _s.name}", package: "${(_t = plugin.ios) === null || _t === void 0 ? void 0 : _t.name}"${aliasText})`;
146
162
  if ((0, plugin_1.getPluginType)(plugin, config.ios.name) === 1 /* PluginType.Cordova */) {
147
163
  const platformTag = (0, plugin_1.getPluginPlatform)(plugin, config.ios.name);
148
- if ((_o = platformTag.$) === null || _o === void 0 ? void 0 : _o.package) {
149
- pluginText = `,\n .product(name: "${plugin.id}", package: "${plugin.id}")`;
164
+ if ((_u = platformTag.$) === null || _u === void 0 ? void 0 : _u.package) {
165
+ pluginText = `,\n .product(name: "${plugin.id}", package: "${plugin.id}"${aliasText})`;
150
166
  }
151
167
  else {
152
168
  const sourceFiles = (0, plugin_1.getPlatformElement)(plugin, config.ios.name, 'source-file');
@@ -206,6 +222,40 @@ async function addInfoPlistDebugIfNeeded(config) {
206
222
  }
207
223
  }
208
224
  exports.addInfoPlistDebugIfNeeded = addInfoPlistDebugIfNeeded;
225
+ function hasSceneManifest(config) {
226
+ const infoPlist = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist');
227
+ if (!(0, fs_extra_1.existsSync)(infoPlist)) {
228
+ return false;
229
+ }
230
+ const entries = (0, plist_1.parse)((0, fs_extra_1.readFileSync)(infoPlist, 'utf-8'));
231
+ return entries['UIApplicationSceneManifest'] !== undefined;
232
+ }
233
+ exports.hasSceneManifest = hasSceneManifest;
234
+ async function addSceneManifestIfNeeded(config) {
235
+ const infoPlist = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist');
236
+ if (!(0, fs_extra_1.existsSync)(infoPlist)) {
237
+ log_1.logger.warn(infoPlist + ' not found.');
238
+ return;
239
+ }
240
+ const entries = (0, plist_1.parse)((0, fs_extra_1.readFileSync)(infoPlist, 'utf-8'));
241
+ if (entries['UIApplicationSceneManifest'] !== undefined) {
242
+ log_1.logger.warn('Found UIApplicationSceneManifest in ' + infoPlist + ', skipping.');
243
+ return;
244
+ }
245
+ entries['UIApplicationSceneManifest'] = {
246
+ UIApplicationSupportsMultipleScenes: false,
247
+ UISceneConfigurations: {
248
+ UIWindowSceneSessionRoleApplication: [
249
+ {
250
+ UISceneConfigurationName: 'Default Configuration',
251
+ UISceneDelegateClassName: '$(PRODUCT_MODULE_NAME).SceneDelegate',
252
+ },
253
+ ],
254
+ },
255
+ };
256
+ (0, fs_extra_1.writeFileSync)(infoPlist, (0, plist_1.build)(entries));
257
+ }
258
+ exports.addSceneManifestIfNeeded = addSceneManifestIfNeeded;
209
259
  async function checkSwiftToolsVersion(config, version) {
210
260
  if (!version) {
211
261
  return null;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findGroupUuidByComment = exports.addSwiftFileToAppTarget = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const path_1 = require("path");
6
+ const xcode_1 = require("xcode");
7
+ /**
8
+ * Register a Swift source file with the first native target of an Xcode project.
9
+ *
10
+ * Writes entries in PBXFileReference, PBXBuildFile, the named PBXGroup's children,
11
+ * and the target's Sources build phase. Idempotent: a second call is a no-op.
12
+ *
13
+ * @param pbxprojPath Absolute path to project.pbxproj
14
+ * @param groupName Comment/name of the PBXGroup the file belongs under (e.g. 'App')
15
+ * @param fileRelPath Path of the file relative to the group (e.g. 'SceneDelegate.swift')
16
+ */
17
+ function addSwiftFileToAppTarget(pbxprojPath, groupName, fileRelPath) {
18
+ const project = (0, xcode_1.project)(pbxprojPath);
19
+ project.parseSync();
20
+ const targetUuid = project.getFirstTarget().uuid;
21
+ if (project.hasFile(fileRelPath) && isSwiftFileInTargetSources(project, fileRelPath, targetUuid)) {
22
+ return { added: false };
23
+ }
24
+ const groupUuid = findGroupUuidByComment(project, groupName);
25
+ if (!groupUuid) {
26
+ throw new Error(`Could not find PBXGroup with comment "${groupName}" in ${pbxprojPath}`);
27
+ }
28
+ if (project.hasFile(fileRelPath) && !isSwiftFileInTargetSources(project, fileRelPath, targetUuid)) {
29
+ const fileRefUuid = findFileRefUuid(project, fileRelPath);
30
+ if (!fileRefUuid) {
31
+ throw new Error(`Could not find PBXFileReference for ${fileRelPath} in ${pbxprojPath}`);
32
+ }
33
+ const group = project.getPBXGroupByKey(groupUuid);
34
+ if (group && !group.children.some((child) => child.comment === fileRelPath)) {
35
+ group.children.push({ value: fileRefUuid, comment: fileRelPath });
36
+ }
37
+ const file = {
38
+ fileRef: fileRefUuid,
39
+ path: fileRelPath,
40
+ basename: (0, path_1.basename)(fileRelPath),
41
+ group: 'Sources',
42
+ target: targetUuid,
43
+ uuid: project.generateUuid(),
44
+ };
45
+ project.addToPbxBuildFileSection(file);
46
+ project.addToPbxSourcesBuildPhase(file);
47
+ (0, fs_extra_1.writeFileSync)(pbxprojPath, project.writeSync(), 'utf-8');
48
+ return { added: true };
49
+ }
50
+ const result = project.addSourceFile(fileRelPath, { target: targetUuid }, groupUuid);
51
+ if (!result) {
52
+ throw new Error(`Failed to register ${fileRelPath} in ${pbxprojPath}`);
53
+ }
54
+ (0, fs_extra_1.writeFileSync)(pbxprojPath, project.writeSync(), 'utf-8');
55
+ return { added: true };
56
+ }
57
+ exports.addSwiftFileToAppTarget = addSwiftFileToAppTarget;
58
+ function fileReferenceMatchesPath(ref, fileRelPath) {
59
+ const path = ref.path;
60
+ return path === fileRelPath || path === `"${fileRelPath}"`;
61
+ }
62
+ function findFileRefUuid(project, fileRelPath) {
63
+ var _a;
64
+ const objects = project.hash.project.objects;
65
+ const fileRefs = Object.entries(objects.PBXFileReference).filter(([k]) => !k.endsWith('_comment'));
66
+ const fileRefEntry = fileRefs.find(([, ref]) => typeof ref === 'object' && fileReferenceMatchesPath(ref, fileRelPath));
67
+ return (_a = fileRefEntry === null || fileRefEntry === void 0 ? void 0 : fileRefEntry[0]) !== null && _a !== void 0 ? _a : null;
68
+ }
69
+ function isSwiftFileInTargetSources(project, fileRelPath, targetUuid) {
70
+ const fileRefUuid = findFileRefUuid(project, fileRelPath);
71
+ if (!fileRefUuid) {
72
+ return false;
73
+ }
74
+ const objects = project.hash.project.objects;
75
+ const sourcesPhase = project.pbxSourcesBuildPhaseObj(targetUuid);
76
+ if (!(sourcesPhase === null || sourcesPhase === void 0 ? void 0 : sourcesPhase.files)) {
77
+ return false;
78
+ }
79
+ return sourcesPhase.files.some((file) => {
80
+ var _a;
81
+ const buildFile = objects.PBXBuildFile[(_a = file.value) !== null && _a !== void 0 ? _a : ''];
82
+ return typeof buildFile === 'object' && (buildFile === null || buildFile === void 0 ? void 0 : buildFile.fileRef) === fileRefUuid;
83
+ });
84
+ }
85
+ // Exported for tests.
86
+ function findGroupUuidByComment(project, comment) {
87
+ const groups = project.hash.project.objects.PBXGroup;
88
+ const COMMENT_SUFFIX = '_comment';
89
+ for (const key of Object.keys(groups)) {
90
+ if (!key.endsWith(COMMENT_SUFFIX))
91
+ continue;
92
+ if (groups[key] === comment) {
93
+ return key.substring(0, key.length - COMMENT_SUFFIX.length);
94
+ }
95
+ }
96
+ return null;
97
+ }
98
+ exports.findGroupUuidByComment = findGroupUuidByComment;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor-plus/cli",
3
- "version": "8.3.12",
3
+ "version": "8.5.1",
4
4
  "description": "Capacitor+: Enhanced Capacitor with automated upstream sync - Cross-platform apps with JavaScript and the web",
5
5
  "homepage": "https://capgo.app/docs/plugins/capacitor-plus/",
6
6
  "author": "Capgo Team <support@capgo.app> (https://capgo.app)",
@@ -60,6 +60,8 @@
60
60
  "semver": "^7.6.3",
61
61
  "tar": "^7.5.3",
62
62
  "tslib": "^2.8.1",
63
+ "typescript": "~5.0.2",
64
+ "xcode": "^3.0.1",
63
65
  "xml2js": "^0.6.2"
64
66
  },
65
67
  "devDependencies": {
@@ -70,6 +72,7 @@
70
72
  "@types/prompts": "^2.4.9",
71
73
  "@types/semver": "^7.5.8",
72
74
  "@types/tmp": "^0.2.6",
75
+ "@types/xcode": "^3.0.0",
73
76
  "@types/xml2js": "0.4.5",
74
77
  "jest": "^29.7.0",
75
78
  "jest-environment-jsdom": "^29.7.0",