@capacitor/cli 9.0.0-alpha.7 → 9.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 (45) hide show
  1. package/assets/android-template.tar.gz +0 -0
  2. package/assets/capacitor-cordova-android-plugins.tar.gz +0 -0
  3. package/assets/capacitor-cordova-ios-plugins.tar.gz +0 -0
  4. package/assets/ios-pods-template.tar.gz +0 -0
  5. package/assets/ios-spm-template.tar.gz +0 -0
  6. package/dist/android/network-security-config.js +230 -0
  7. package/dist/android/update.js +5 -1
  8. package/dist/common.js +1 -1
  9. package/dist/config.js +4 -3
  10. package/dist/cordova.js +8 -17
  11. package/dist/declarations.d.ts +8 -41
  12. package/dist/index.js +4 -14
  13. package/dist/ios/common.js +1 -1
  14. package/dist/ios/update.js +9 -17
  15. package/dist/ipc.js +51 -11
  16. package/dist/plugin.js +1 -1
  17. package/dist/run-context/declared.js +54 -0
  18. package/dist/run-context/index.js +111 -0
  19. package/dist/run-context/registry.js +45 -0
  20. package/dist/run-context/signals.js +115 -0
  21. package/dist/run-context/types.js +2 -0
  22. package/dist/run-context/unknown.js +46 -0
  23. package/dist/run-context/version.js +74 -0
  24. package/dist/tasks/copy.js +3 -1
  25. package/dist/tasks/doctor.js +4 -1
  26. package/dist/tasks/list.js +1 -1
  27. package/dist/tasks/migrate-debug-xcconfig.js +60 -0
  28. package/dist/tasks/migrate-spm.js +0 -1
  29. package/dist/tasks/migrate-swiftui.js +344 -54
  30. package/dist/tasks/migrate-to-modern-project.js +27 -0
  31. package/dist/tasks/migrate.js +41 -4
  32. package/dist/tasks/run.js +8 -3
  33. package/dist/tasks/telemetry.js +8 -1
  34. package/dist/telemetry.js +303 -57
  35. package/dist/util/capacitor-package.js +95 -146
  36. package/dist/util/cordova-ios.js +13 -8
  37. package/dist/util/js.js +1 -1
  38. package/dist/util/monorepotools.js +2 -2
  39. package/dist/util/node.js +3 -3
  40. package/dist/util/npm.js +120 -0
  41. package/dist/util/spm.js +35 -25
  42. package/dist/util/subprocess.js +2 -2
  43. package/dist/util/xcode.js +193 -2
  44. package/dist/util/xml.js +1 -1
  45. package/package.json +3 -2
@@ -1,68 +1,77 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findCapacitorDependencyVersion = exports.rewriteCapacitorDependency = exports.renderCapacitorPackage = exports.resolveCapacitorPackage = void 0;
3
+ exports.patchPackageSwiftDeploymentTarget = exports.findCapacitorDependencyVersion = exports.rewriteCapacitorDependency = exports.renderCapacitorPackage = exports.resolveCapacitorPackagePath = exports.CORDOVA_PRODUCT = exports.SOURCE_PACKAGE_IDENTITY = void 0;
4
4
  const fs_extra_1 = require("fs-extra");
5
5
  const path_1 = require("path");
6
- const semver_1 = require("semver");
7
- const common_1 = require("../common");
8
6
  const errors_1 = require("../errors");
9
7
  const fs_1 = require("./fs");
10
- /** Capacitor 9 and up builds the iOS platform from source out of the main repo. */
11
- const SOURCE_PACKAGE_MAJOR = 9;
8
+ const node_1 = require("./node");
12
9
  const SOURCE_PACKAGE_URL = 'https://github.com/ionic-team/capacitor';
13
- const SOURCE_PACKAGE_IDENTITY = 'capacitor';
14
- /** Before Capacitor 9 the platform was consumed as a prebuilt xcframework from a separate repo. */
15
- const BINARY_PACKAGE_URL = 'https://github.com/ionic-team/capacitor-swift-pm.git';
10
+ exports.SOURCE_PACKAGE_IDENTITY = 'capacitor';
11
+ const SOURCE_PACKAGE_NAME = new RegExp(`name:\\s*"${exports.SOURCE_PACKAGE_IDENTITY}"`);
12
+ /** Product providing the Cordova compatibility layer. */
13
+ exports.CORDOVA_PRODUCT = 'CapacitorCordova';
14
+ /** The npm package the Swift package ships inside. */
15
+ const PLATFORM_PACKAGE = '@capacitor/ios';
16
+ /** Plugins published before Capacitor 9 depend on the platform as a prebuilt xcframework. */
16
17
  const BINARY_PACKAGE_IDENTITY = 'capacitor-swift-pm';
17
- const ENV_OVERRIDE = 'CAPACITOR_IOS_PACKAGE';
18
- const REQUIREMENT_KEYS = ['path', 'branch', 'revision', 'exact', 'from'];
19
18
  /**
20
- * Resolves which Capacitor Swift package generated `Package.swift` files should depend on.
19
+ * Resolves the Capacitor Swift package generated `Package.swift` files should depend on: the
20
+ * `@capacitor/ios` npm already installed in the app, which ships the package alongside the sources.
21
21
  *
22
- * Precedence, most specific first:
23
- * 1. the `CAPACITOR_IOS_PACKAGE` environment variable
24
- * 2. `experimental.ios.spm.capacitorPackage` in the Capacitor config
25
- * 3. the git tag matching the installed `@capacitor/ios` version
26
- *
27
- * The environment variable deliberately outranks the config file so a checkout can be pointed at a
28
- * local or branch build without editing (and risking committing) the app's configuration.
22
+ * Resolving from `node_modules` keeps the native runtime and the `@capacitor/core` bridge it is
23
+ * versioned against on the same release, with no git tag to line up against the npm version. It
24
+ * also carries no version for the app package and any generated plugin packages to disagree about.
25
+ */
26
+ async function resolveCapacitorPackagePath(config) {
27
+ const packageJsonPath = (0, node_1.resolveNode)(config.app.rootDir, PLATFORM_PACKAGE, 'package.json');
28
+ if (!packageJsonPath) {
29
+ (0, errors_1.fatal)(`Unable to find node_modules/${PLATFORM_PACKAGE}.\nAre you sure ${PLATFORM_PACKAGE} is installed?`);
30
+ }
31
+ const absolutePath = installDirectory((0, path_1.dirname)(packageJsonPath), config.app.rootDir);
32
+ if (!(0, fs_extra_1.existsSync)((0, path_1.resolve)(absolutePath, 'Package.swift'))) {
33
+ (0, errors_1.fatal)(`The installed ${PLATFORM_PACKAGE} has no Package.swift (looked in ${absolutePath}).\n` +
34
+ `Early 9.0.0 alphas did not ship one; update ${PLATFORM_PACKAGE} to build with SPM.`);
35
+ }
36
+ return absolutePath;
37
+ }
38
+ exports.resolveCapacitorPackagePath = resolveCapacitorPackagePath;
39
+ /**
40
+ * Trades the resolved location for the `node_modules` entry that leads to it, when there is one.
29
41
  *
30
- * `legacyRequirement` only applies to pre-9 projects, where it preserves each caller's existing
31
- * requirement style. Source-based projects always pin `exact`, because the app package and any
32
- * generated plugin packages must agree: a prerelease such as `9.0.0-alpha.6` does not satisfy a
33
- * `from:` range, so mixing the two styles fails to resolve.
42
+ * Node resolves symlinks away, so a linked or `file:`-installed package resolves to wherever it
43
+ * actually lives — an absolute path outside the app, which the generated `Package.swift` is
44
+ * committed with. The entry inside the project stays valid on every machine.
34
45
  */
35
- async function resolveCapacitorPackage(config, legacyRequirement = 'exact') {
36
- var _a, _b;
37
- const version = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name);
38
- if ((0, semver_1.major)(version) < SOURCE_PACKAGE_MAJOR) {
39
- return {
40
- identity: BINARY_PACKAGE_IDENTITY,
41
- cordovaProduct: 'Cordova',
42
- sourceBased: false,
43
- url: BINARY_PACKAGE_URL,
44
- requirement: { kind: legacyRequirement, version },
45
- };
46
+ function installDirectory(resolved, rootDir) {
47
+ const real = realPath(resolved);
48
+ if (!real) {
49
+ return resolved;
50
+ }
51
+ for (let dir = (0, path_1.resolve)(rootDir);; dir = (0, path_1.dirname)(dir)) {
52
+ const candidate = (0, path_1.resolve)(dir, 'node_modules', PLATFORM_PACKAGE);
53
+ if (realPath(candidate) === real) {
54
+ return candidate;
55
+ }
56
+ if ((0, path_1.dirname)(dir) === dir) {
57
+ return resolved;
58
+ }
46
59
  }
47
- const override = resolveOverride(config);
48
- return {
49
- identity: SOURCE_PACKAGE_IDENTITY,
50
- cordovaProduct: 'CapacitorCordova',
51
- sourceBased: true,
52
- url: (_a = override === null || override === void 0 ? void 0 : override.url) !== null && _a !== void 0 ? _a : SOURCE_PACKAGE_URL,
53
- requirement: (_b = override === null || override === void 0 ? void 0 : override.requirement) !== null && _b !== void 0 ? _b : { kind: 'exact', version },
54
- };
55
60
  }
56
- exports.resolveCapacitorPackage = resolveCapacitorPackage;
57
- /** Renders the `.package(...)` entry, with any path made relative to the file being written. */
58
- function renderCapacitorPackage(pkg, fromDir) {
59
- if (pkg.requirement.kind === 'path') {
60
- const relPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(fromDir, pkg.requirement.absolutePath));
61
- // Pin the identity: for a path dependency SPM would otherwise derive it from the directory
62
- // name, which breaks `.product(package:)` when the checkout is not named "capacitor".
63
- return `.package(name: "${pkg.identity}", path: "${relPath}")`;
61
+ function realPath(path) {
62
+ try {
63
+ return (0, fs_extra_1.realpathSync)(path);
64
+ }
65
+ catch {
66
+ return undefined;
64
67
  }
65
- return `.package(url: "${pkg.url}", ${renderRequirement(pkg.requirement)})`;
68
+ }
69
+ /** Renders the `.package(...)` entry, with the path made relative to the file being written. */
70
+ function renderCapacitorPackage(absolutePath, fromDir) {
71
+ const relPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(fromDir, absolutePath));
72
+ // Pin the identity: for a path dependency SPM would otherwise derive it from the directory
73
+ // name, which breaks `.product(package:)` when the checkout is not named "capacitor".
74
+ return `.package(name: "${exports.SOURCE_PACKAGE_IDENTITY}", path: "${relPath}")`;
66
75
  }
67
76
  exports.renderCapacitorPackage = renderCapacitorPackage;
68
77
  /**
@@ -73,12 +82,9 @@ exports.renderCapacitorPackage = renderCapacitorPackage;
73
82
  * `Capacitor` product — so a plugin left untouched would either fail to resolve or link a second
74
83
  * copy of the framework. Rewriting keeps the whole graph on one identity.
75
84
  */
76
- function rewriteCapacitorDependency(content, pkg, fromDir) {
77
- let rewritten = replacePackageCalls(content, renderCapacitorPackage(pkg, fromDir));
78
- for (const identity of [BINARY_PACKAGE_IDENTITY, SOURCE_PACKAGE_IDENTITY]) {
79
- rewritten = rewritten.split(`package: "${identity}"`).join(`package: "${pkg.identity}"`);
80
- }
81
- return rewritten;
85
+ function rewriteCapacitorDependency(content, absolutePath, fromDir) {
86
+ const rewritten = replacePackageCalls(content, renderCapacitorPackage(absolutePath, fromDir));
87
+ return rewritten.split(`package: "${BINARY_PACKAGE_IDENTITY}"`).join(`package: "${exports.SOURCE_PACKAGE_IDENTITY}"`);
82
88
  }
83
89
  exports.rewriteCapacitorDependency = rewriteCapacitorDependency;
84
90
  /** Reads the version an existing `Package.swift` pins Capacitor to, if it pins one. */
@@ -95,8 +101,40 @@ function findCapacitorDependencyVersion(content) {
95
101
  return undefined;
96
102
  }
97
103
  exports.findCapacitorDependencyVersion = findCapacitorDependencyVersion;
104
+ const IOS_PLATFORM_VERSION_REGEX = /\.iOS\(\s*(?:\.v(\d+)|"([\d.]+)")\s*\)/;
105
+ /**
106
+ * Bumps a Package.swift's declared iOS deployment target (e.g. `.iOS(.v13)` or `.iOS("14.0")`) up to
107
+ * `requiredIosVersion` if it's lower.
108
+ *
109
+ * Only relevant for the source package: it declares `platforms: [.iOS(.v16)]` on its own manifest,
110
+ * and SwiftPM enforces that across the whole graph, so a plugin still declaring an older, lower
111
+ * target fails to resolve with "requires minimum platform version X ... but this target supports Y" —
112
+ * even though the very same plugin links fine against the prebuilt `capacitor-swift-pm`, which never
113
+ * declared a `platforms:` entry for SwiftPM to check against.
114
+ */
115
+ function patchPackageSwiftDeploymentTarget(content, requiredIosVersion) {
116
+ const match = content.match(IOS_PLATFORM_VERSION_REGEX);
117
+ if (!match) {
118
+ return { content, changed: false, previousVersion: null };
119
+ }
120
+ const isSymbolic = match[1] !== undefined;
121
+ const previousVersion = isSymbolic ? match[1] : match[2];
122
+ const requiredMajor = Math.trunc(parseFloat(requiredIosVersion));
123
+ if (parseFloat(previousVersion) >= requiredMajor) {
124
+ return { content, changed: false, previousVersion };
125
+ }
126
+ const replacement = isSymbolic ? `.iOS(.v${requiredMajor})` : `.iOS("${requiredMajor}.0")`;
127
+ const patchedContent = content.replace(IOS_PLATFORM_VERSION_REGEX, replacement);
128
+ return { content: patchedContent, changed: true, previousVersion };
129
+ }
130
+ exports.patchPackageSwiftDeploymentTarget = patchPackageSwiftDeploymentTarget;
131
+ /**
132
+ * A path dependency carries no URL to match on, so it is matched on its pinned identity — without
133
+ * that, a manifest rewritten by an earlier sync keeps a relative path that no longer resolves once
134
+ * the app, or the package it points at, has moved.
135
+ */
98
136
  function referencesCapacitor(call) {
99
- return call.includes(BINARY_PACKAGE_IDENTITY) || call.includes(`${SOURCE_PACKAGE_URL}`);
137
+ return call.includes(BINARY_PACKAGE_IDENTITY) || call.includes(SOURCE_PACKAGE_URL) || SOURCE_PACKAGE_NAME.test(call);
100
138
  }
101
139
  /**
102
140
  * Locates `.package(...)` calls in code, skipping any inside a comment or string literal.
@@ -206,92 +244,3 @@ function startOfEntry(content, start) {
206
244
  }
207
245
  return content[cursor] === ',' ? cursor : start;
208
246
  }
209
- function renderRequirement(requirement) {
210
- switch (requirement.kind) {
211
- case 'branch':
212
- return `branch: "${requirement.branch}"`;
213
- case 'revision':
214
- return `revision: "${requirement.revision}"`;
215
- case 'exact':
216
- return `exact: "${requirement.version}"`;
217
- case 'from':
218
- return `from: "${requirement.version}"`;
219
- case 'path':
220
- throw new Error('path requirements are rendered by renderCapacitorPackage');
221
- }
222
- }
223
- function resolveOverride(config) {
224
- var _a, _b, _c, _d;
225
- const baseDir = config.app.rootDir;
226
- const fromEnv = (_a = process.env[ENV_OVERRIDE]) === null || _a === void 0 ? void 0 : _a.trim();
227
- if (fromEnv) {
228
- return { requirement: parseRequirementSpec(fromEnv, baseDir) };
229
- }
230
- const fromConfig = (_d = (_c = (_b = config.app.extConfig.experimental) === null || _b === void 0 ? void 0 : _b.ios) === null || _c === void 0 ? void 0 : _c.spm) === null || _d === void 0 ? void 0 : _d.capacitorPackage;
231
- if (!fromConfig) {
232
- return undefined;
233
- }
234
- const provided = REQUIREMENT_KEYS.filter((key) => fromConfig[key] !== undefined);
235
- if (provided.length === 0) {
236
- (0, errors_1.fatal)(`experimental.ios.spm.capacitorPackage must set one of: ${REQUIREMENT_KEYS.join(', ')}.\n` +
237
- `Remove the entry to use the version matching the installed @capacitor/ios.`);
238
- }
239
- if (provided.length > 1) {
240
- (0, errors_1.fatal)(`experimental.ios.spm.capacitorPackage sets more than one of: ${provided.join(', ')}.\n` + `Only one may be set.`);
241
- }
242
- const key = provided[0];
243
- const value = String(fromConfig[key]);
244
- if (key === 'path') {
245
- if (fromConfig.url !== undefined) {
246
- (0, errors_1.fatal)(`experimental.ios.spm.capacitorPackage cannot set both "url" and "path".`);
247
- }
248
- return { requirement: pathRequirement(value, baseDir) };
249
- }
250
- return { url: fromConfig.url, requirement: { kind: key, ...requirementValue(key, value) } };
251
- }
252
- function requirementValue(key, value) {
253
- switch (key) {
254
- case 'branch':
255
- return { branch: value };
256
- case 'revision':
257
- return { revision: value };
258
- default:
259
- return { version: value };
260
- }
261
- }
262
- /**
263
- * Parses a `CAPACITOR_IOS_PACKAGE` value. Accepts an explicit `kind:value` form, or infers `path`
264
- * for anything path-shaped and `exact` for a bare version.
265
- */
266
- function parseRequirementSpec(spec, baseDir) {
267
- const separator = spec.indexOf(':');
268
- if (separator > 0) {
269
- const key = spec.slice(0, separator);
270
- const value = spec.slice(separator + 1);
271
- if (REQUIREMENT_KEYS.includes(key)) {
272
- if (key === 'path') {
273
- return pathRequirement(value, baseDir);
274
- }
275
- return {
276
- kind: key,
277
- ...requirementValue(key, value),
278
- };
279
- }
280
- }
281
- if (spec.startsWith('.') || (0, path_1.isAbsolute)(spec)) {
282
- return pathRequirement(spec, baseDir);
283
- }
284
- if ((0, semver_1.valid)(spec)) {
285
- return { kind: 'exact', version: spec };
286
- }
287
- return (0, errors_1.fatal)(`Could not understand ${ENV_OVERRIDE}="${spec}".\n` +
288
- `Expected one of ${REQUIREMENT_KEYS.map((k) => `${k}:<value>`).join(', ')}, a path, or a version.`);
289
- }
290
- function pathRequirement(value, baseDir) {
291
- const absolutePath = (0, path_1.resolve)(baseDir, value);
292
- if (!(0, fs_extra_1.existsSync)((0, path_1.resolve)(absolutePath, 'Package.swift'))) {
293
- (0, errors_1.fatal)(`No Package.swift found at ${absolutePath}.\n` +
294
- `A local Capacitor package must point at the repository root, not the ios directory.`);
295
- }
296
- return { kind: 'path', absolutePath };
297
- }
@@ -218,6 +218,10 @@ async function copyPluginsNativeFiles(config, cordovaPlugins) {
218
218
  fileContent = fileContent.replace(/self.webView.superview/g, 'self.viewController.view');
219
219
  await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' });
220
220
  }
221
+ if (isSPM && fileContent.includes(`#import "AppDelegate.h"`)) {
222
+ fileContent = fileContent.replace(`#import "AppDelegate.h"`, `#import <Cordova/AppDelegate.h>`);
223
+ await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' });
224
+ }
221
225
  }
222
226
  }
223
227
  }
@@ -316,9 +320,9 @@ function filterResources(plugin) {
316
320
  return resources.length > 0;
317
321
  }
318
322
  async function generateCordovaPackageFiles(cordovaPlugins, config) {
319
- cordovaPlugins.map((plugin) => {
320
- generateCordovaPackageFile(plugin, config);
321
- });
323
+ await Promise.all(cordovaPlugins.map(async (plugin) => {
324
+ await generateCordovaPackageFile(plugin, config);
325
+ }));
322
326
  }
323
327
  exports.generateCordovaPackageFiles = generateCordovaPackageFiles;
324
328
  function buildBinaryTargetEntries(p, frameworks) {
@@ -435,7 +439,7 @@ ${entries.join(',\n')}
435
439
  }
436
440
  async function generateCordovaPackageFile(p, config) {
437
441
  var _a;
438
- const capacitorPackage = await (0, capacitor_package_1.resolveCapacitorPackage)(config, 'from');
442
+ const capacitorPackagePath = await (0, capacitor_package_1.resolveCapacitorPackagePath)(config);
439
443
  const iosVersion = (0, common_1.getMajoriOSVersion)(config);
440
444
  const headerFiles = (0, plugin_1.getPlatformElement)(p, platform, 'header-file');
441
445
  let headersText = '';
@@ -447,8 +451,9 @@ async function generateCordovaPackageFile(p, config) {
447
451
  if ((_a = platformTag.$) === null || _a === void 0 ? void 0 : _a.package) {
448
452
  const packageSwiftPath = (0, path_1.join)(p.rootPath, 'Package.swift');
449
453
  let content = await (0, fs_extra_1.readFile)(packageSwiftPath, { encoding: 'utf-8' });
450
- content = content.replace(`apache`, `ionic-team`).replaceAll(`cordova-ios`, capacitorPackage.identity);
451
- content = (0, capacitor_package_1.rewriteCapacitorDependency)(content, capacitorPackage, p.rootPath);
454
+ content = content.replace(`apache`, `ionic-team`).replaceAll(`cordova-ios`, capacitor_package_1.SOURCE_PACKAGE_IDENTITY);
455
+ content = (0, capacitor_package_1.rewriteCapacitorDependency)(content, capacitorPackagePath, p.rootPath);
456
+ content = (0, capacitor_package_1.patchPackageSwiftDeploymentTarget)(content, iosVersion).content;
452
457
  await (0, fs_extra_1.writeFile)(packageSwiftPath, content);
453
458
  }
454
459
  else {
@@ -486,13 +491,13 @@ let package = Package(
486
491
  )
487
492
  ],
488
493
  dependencies: [
489
- ${(0, capacitor_package_1.renderCapacitorPackage)(capacitorPackage, (0, path_1.join)(config.ios.cordovaPluginsDirAbs, 'sources', p.name))}${packageText}
494
+ ${(0, capacitor_package_1.renderCapacitorPackage)(capacitorPackagePath, (0, path_1.join)(config.ios.cordovaPluginsDirAbs, 'sources', p.name))}${packageText}
490
495
  ],
491
496
  targets: [
492
497
  .target(
493
498
  name: "${p.name}",
494
499
  dependencies: [
495
- .product(name: "Cordova", package: "${capacitorPackage.identity}")${binaryDepsText}${productText}
500
+ .product(name: "Cordova", package: "${capacitor_package_1.SOURCE_PACKAGE_IDENTITY}")${binaryDepsText}${productText}
496
501
  ],
497
502
  path: "."${resourcesText}${headersText}${cSettingsText}${linkerSettingsText}
498
503
  )${binaryTargetsText}
package/dist/util/js.js CHANGED
@@ -8,7 +8,7 @@ function formatJSObject(o) {
8
8
  o = JSON.parse(JSON.stringify(o));
9
9
  }
10
10
  catch (e) {
11
- throw new Error(`Cannot parse object as JSON: ${e.stack ? e.stack : e}`);
11
+ throw new Error(`Cannot parse object as JSON: ${e.stack ? e.stack : e}`, { cause: e });
12
12
  }
13
13
  return util_1.default.inspect(o, {
14
14
  compact: false,
@@ -87,7 +87,7 @@ function isMonorepo(currentPath) {
87
87
  findMonorepoRoot(currentPath);
88
88
  return true;
89
89
  }
90
- catch (error) {
90
+ catch {
91
91
  return false;
92
92
  }
93
93
  }
@@ -102,7 +102,7 @@ function isNXMonorepo(currentPath) {
102
102
  findNXMonorepoRoot(currentPath);
103
103
  return true;
104
104
  }
105
- catch (error) {
105
+ catch {
106
106
  return false;
107
107
  }
108
108
  }
package/dist/util/node.js CHANGED
@@ -38,7 +38,7 @@ const requireTS = async (ts, p) => {
38
38
  if ((e === null || e === void 0 ? void 0 : e.code) === 'ERR_UNKNOWN_FILE_EXTENSION') {
39
39
  throw new Error(`Your installed version of TypeScript (${ts.version}) no longer provides the compiler API Capacitor previously used to load .ts config files, ` +
40
40
  `and your Node.js runtime (${process.version}) doesn't support loading them natively either.\n` +
41
- 'Upgrade to Node.js 22.6+ (running with --experimental-strip-types), or Node.js 23.6+, to continue using capacitor.config.ts.');
41
+ 'Upgrade to Node.js 22.6+ (running with --experimental-strip-types), or Node.js 23.6+, to continue using capacitor.config.ts.', { cause: e });
42
42
  }
43
43
  throw e;
44
44
  }
@@ -68,7 +68,7 @@ const requireTS = async (ts, p) => {
68
68
  }
69
69
  (_a = module._compile) === null || _a === void 0 ? void 0 : _a.call(module, sourceText, fileName);
70
70
  };
71
- const m = require(id); // eslint-disable-line @typescript-eslint/no-var-requires
71
+ const m = require(id); // eslint-disable-line @typescript-eslint/no-require-imports
72
72
  delete require.extensions['.ts'];
73
73
  return m;
74
74
  };
@@ -77,7 +77,7 @@ function resolveNode(root, ...pathSegments) {
77
77
  try {
78
78
  return require.resolve(pathSegments.join('/'), { paths: [root] });
79
79
  }
80
- catch (e) {
80
+ catch {
81
81
  const path = [root, 'node_modules', ...pathSegments].join('/');
82
82
  if ((0, fs_1.existsSync)(path)) {
83
83
  return path;
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logBlockedInstallScripts = exports.hasBlockedCapacitorScripts = exports.parseBlockedInstallScripts = exports.getBlockedInstallScripts = exports.isNpmProject = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_extra_1 = require("fs-extra");
6
+ const path_1 = require("path");
7
+ const colors_1 = tslib_1.__importDefault(require("../colors"));
8
+ const log_1 = require("../log");
9
+ const subprocess_1 = require("./subprocess");
10
+ const LOCKFILE_MANAGERS = [
11
+ ['package-lock.json', 'npm'],
12
+ ['npm-shrinkwrap.json', 'npm'],
13
+ ['pnpm-lock.yaml', 'pnpm'],
14
+ ['yarn.lock', 'yarn'],
15
+ ['bun.lock', 'bun'],
16
+ ['bun.lockb', 'bun'],
17
+ ];
18
+ /**
19
+ * `npm install-scripts ls` compares the tree against npm's own `allowScripts` map, which yarn and
20
+ * pnpm never write. It therefore reports every install script in a yarn or pnpm project as
21
+ * blocked, even when that package manager ran it, so the check has to know who did the install.
22
+ *
23
+ * Only a positive signal counts. `rootDir` is the app package, which in a workspace holds neither
24
+ * a lockfile nor a `packageManager` field, and guessing npm there reports blocked scripts for an
25
+ * install npm never performed.
26
+ */
27
+ async function isNpmProject(rootDir) {
28
+ try {
29
+ const { packageManager } = await (0, fs_extra_1.readJSON)((0, path_1.join)(rootDir, 'package.json'));
30
+ if (typeof packageManager === 'string') {
31
+ return packageManager.split('@')[0] === 'npm';
32
+ }
33
+ }
34
+ catch {
35
+ // no package.json, or an unreadable one: fall through to the lockfiles
36
+ }
37
+ for (const [lockfile, manager] of LOCKFILE_MANAGERS) {
38
+ if ((0, fs_extra_1.existsSync)((0, path_1.join)(rootDir, lockfile))) {
39
+ return manager === 'npm';
40
+ }
41
+ }
42
+ return false;
43
+ }
44
+ exports.isNpmProject = isNpmProject;
45
+ /**
46
+ * npm 12 blocks dependency install scripts by default and still exits 0, so the only reliable
47
+ * signal is to ask npm directly. `npm install-scripts ls` lists every package whose scripts are
48
+ * still awaiting a decision, and does not exist before npm 12, where the command exits non-zero
49
+ * and `getCommandOutput` hands back null.
50
+ *
51
+ * Pass `packageManager` when the caller already knows which one ran the install; otherwise it is
52
+ * inferred from the project.
53
+ */
54
+ async function getBlockedInstallScripts(rootDir, packageManager) {
55
+ const isNpm = packageManager === undefined ? await isNpmProject(rootDir) : packageManager.toLowerCase() === 'npm';
56
+ if (!isNpm) {
57
+ return [];
58
+ }
59
+ return parseBlockedInstallScripts(await (0, subprocess_1.getCommandOutput)('npm', ['install-scripts', 'ls', '--json'], { cwd: rootDir }));
60
+ }
61
+ exports.getBlockedInstallScripts = getBlockedInstallScripts;
62
+ function parseBlockedInstallScripts(commandOutput) {
63
+ if (!commandOutput) {
64
+ return [];
65
+ }
66
+ let parsed;
67
+ try {
68
+ parsed = JSON.parse(commandOutput);
69
+ }
70
+ catch {
71
+ return [];
72
+ }
73
+ if (!Array.isArray(parsed === null || parsed === void 0 ? void 0 : parsed.allowScripts)) {
74
+ return [];
75
+ }
76
+ const blocked = [];
77
+ for (const entry of parsed.allowScripts) {
78
+ const name = entry === null || entry === void 0 ? void 0 : entry.name;
79
+ if (typeof name !== 'string' || !Array.isArray(entry.changes)) {
80
+ continue;
81
+ }
82
+ for (const change of entry.changes) {
83
+ if ((change === null || change === void 0 ? void 0 : change.change) !== 'pending' || typeof change.key !== 'string') {
84
+ continue;
85
+ }
86
+ blocked.push({
87
+ name,
88
+ version: change.key.startsWith(`${name}@`) ? change.key.slice(name.length + 1) : change.key,
89
+ });
90
+ }
91
+ }
92
+ return blocked;
93
+ }
94
+ exports.parseBlockedInstallScripts = parseBlockedInstallScripts;
95
+ /**
96
+ * npm 12 denies install scripts by default, so a typical project has pending entries for packages
97
+ * like esbuild or sharp that a Capacitor migration has no bearing on. Only Capacitor's own blocked
98
+ * scripts say anything about whether the migration finished.
99
+ */
100
+ function hasBlockedCapacitorScripts(blocked) {
101
+ return blocked.some(({ name }) => name.startsWith('@capacitor/'));
102
+ }
103
+ exports.hasBlockedCapacitorScripts = hasBlockedCapacitorScripts;
104
+ function logBlockedInstallScripts(blocked) {
105
+ if (blocked.length === 0) {
106
+ return;
107
+ }
108
+ const names = [...new Set(blocked.map(({ name }) => name))];
109
+ const packages = blocked.map(({ name, version }) => ` ${colors_1.default.strong(`${name}@${version}`)}\n`).join('');
110
+ const approvals = names.map((name) => ` ${colors_1.default.input(`npm install-scripts approve ${name}`)}\n`).join('');
111
+ log_1.output.write(`${colors_1.default.strong('Blocked Install Scripts:')}\n\n` +
112
+ ` npm blocked install scripts for ${names.length === 1 ? '1 package' : `${names.length} packages`}. ` +
113
+ `Features that rely on them may not work.\n\n` +
114
+ packages +
115
+ `\n To allow them, run:\n\n` +
116
+ approvals +
117
+ ` ${colors_1.default.input('npm rebuild')}\n\n` +
118
+ ` ${colors_1.default.weak('Approvals are pinned to an exact version, so repeat this after upgrading the package.')}\n\n`);
119
+ }
120
+ exports.logBlockedInstallScripts = logBlockedInstallScripts;
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.setSwiftUISceneManifest = exports.hasSwiftUISceneManifest = exports.hasSceneManifest = 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.ensureSPMGitignoreEntry = exports.setSwiftUISceneManifest = exports.hasSwiftUISceneManifest = exports.hasSceneManifest = exports.removeInfoPlistDebug = 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");
@@ -60,15 +60,12 @@ exports.checkPluginsForPackageSwift = checkPluginsForPackageSwift;
60
60
  async function extractSPMPackageDirectory(config) {
61
61
  const spmDirectory = (0, path_1.join)(config.ios.nativeProjectDirAbs, 'CapApp-SPM');
62
62
  const spmTemplate = (0, path_1.join)(config.cli.assetsDirAbs, 'ios-spm-template.tar.gz');
63
- const debugConfig = (0, path_1.join)(config.ios.platformDirAbs, 'debug.xcconfig');
64
63
  log_1.logger.info('Extracting ' + spmTemplate + ' to ' + spmDirectory);
65
64
  try {
66
65
  const tempCapDir = await (0, fs_extra_1.mkdtemp)((0, path_1.join)((0, os_1.tmpdir)(), 'cap-'));
67
66
  const tempCapSPM = (0, path_1.join)(tempCapDir, 'App', 'CapApp-SPM');
68
- const tempDebugXCConfig = (0, path_1.join)(tempCapDir, 'debug.xcconfig');
69
67
  await (0, tar_1.extract)({ file: spmTemplate, cwd: tempCapDir });
70
68
  await (0, fs_extra_1.move)(tempCapSPM, spmDirectory);
71
- await (0, fs_extra_1.move)(tempDebugXCConfig, debugConfig);
72
69
  }
73
70
  catch (err) {
74
71
  (0, errors_1.fatal)('Failed to create ' + spmDirectory + ' with error: ' + err);
@@ -92,7 +89,7 @@ async function generatePackageText(config, plugins) {
92
89
  const enableCordova = cordovaPlugins.length > 0 || config.app.forceCordova;
93
90
  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 : {};
94
91
  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 : {};
95
- const capacitorPackage = await (0, capacitor_package_1.resolveCapacitorPackage)(config);
92
+ const capacitorPackagePath = await (0, capacitor_package_1.resolveCapacitorPackagePath)(config);
96
93
  const spmDirectory = (0, path_1.join)(config.ios.nativeProjectDirAbs, 'CapApp-SPM');
97
94
  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';
98
95
  let packageSwiftText = `// swift-tools-version: ${swiftToolsVersion}
@@ -108,7 +105,7 @@ let package = Package(
108
105
  targets: ["CapApp-SPM"])
109
106
  ],
110
107
  dependencies: [
111
- ${(0, capacitor_package_1.renderCapacitorPackage)(capacitorPackage, spmDirectory)}`;
108
+ ${(0, capacitor_package_1.renderCapacitorPackage)(capacitorPackagePath, spmDirectory)}`;
112
109
  for (const plugin of plugins) {
113
110
  if ((0, plugin_1.getPluginType)(plugin, config.ios.name) === 1 /* PluginType.Cordova */) {
114
111
  const platformTag = (0, plugin_1.getPluginPlatform)(plugin, config.ios.name);
@@ -153,9 +150,9 @@ let package = Package(
153
150
  .target(
154
151
  name: "CapApp-SPM",
155
152
  dependencies: [
156
- .product(name: "Capacitor", package: "${capacitorPackage.identity}")`;
153
+ .product(name: "Capacitor", package: "${capacitor_package_1.SOURCE_PACKAGE_IDENTITY}")`;
157
154
  if (enableCordova) {
158
- packageSwiftText += `,\n .product(name: "${capacitorPackage.cordovaProduct}", package: "${capacitorPackage.identity}")`;
155
+ packageSwiftText += `,\n .product(name: "${capacitor_package_1.CORDOVA_PRODUCT}", package: "${capacitor_package_1.SOURCE_PACKAGE_IDENTITY}")`;
159
156
  }
160
157
  for (const plugin of plugins) {
161
158
  const aliases = Object.entries((_r = (_q = packageOptions[plugin.id]) === null || _q === void 0 ? void 0 : _q.moduleAliases) !== null && _r !== void 0 ? _r : {});
@@ -209,27 +206,24 @@ async function runCocoapodsDeintegrate(config) {
209
206
  }
210
207
  }
211
208
  exports.runCocoapodsDeintegrate = runCocoapodsDeintegrate;
212
- async function addInfoPlistDebugIfNeeded(config) {
209
+ /**
210
+ * Drop the CAPACITOR_DEBUG key from Info.plist. Capacitor 9 no longer reads it, and the
211
+ * debug.xcconfig that supplied its $(CAPACITOR_DEBUG) value is gone from the template.
212
+ */
213
+ function removeInfoPlistDebug(config) {
213
214
  const infoPlist = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist');
214
- log_1.logger.info('Checking ' + infoPlist + ' for CAPACITOR_DEBUG');
215
- if ((0, fs_extra_1.existsSync)(infoPlist)) {
216
- const infoPlistContents = (0, fs_extra_1.readFileSync)(infoPlist, 'utf-8');
217
- const plistEntries = (0, plist_1.parse)(infoPlistContents);
218
- if (plistEntries['CAPACITOR_DEBUG'] === undefined) {
219
- log_1.logger.info('Writing CAPACITOR_DEBUG to ' + infoPlist);
220
- plistEntries['CAPACITOR_DEBUG'] = '$(CAPACITOR_DEBUG)';
221
- const plistToWrite = (0, plist_1.build)(plistEntries);
222
- (0, fs_extra_1.writeFileSync)(infoPlist, plistToWrite);
223
- }
224
- else {
225
- log_1.logger.warn('Found CAPACITOR_DEBUG set to ' + plistEntries['CAPACITOR_DEBUG'] + ', skipping.');
226
- }
215
+ if (!(0, fs_extra_1.existsSync)(infoPlist)) {
216
+ return { status: 'skipped', reason: `${infoPlist} not found.` };
227
217
  }
228
- else {
229
- log_1.logger.warn(infoPlist + ' not found.');
218
+ const entries = (0, plist_1.parse)((0, fs_extra_1.readFileSync)(infoPlist, 'utf-8'));
219
+ if (entries['CAPACITOR_DEBUG'] === undefined) {
220
+ return { status: 'unchanged' };
230
221
  }
222
+ delete entries['CAPACITOR_DEBUG'];
223
+ (0, fs_extra_1.writeFileSync)(infoPlist, (0, plist_1.build)(entries));
224
+ return { status: 'removed' };
231
225
  }
232
- exports.addInfoPlistDebugIfNeeded = addInfoPlistDebugIfNeeded;
226
+ exports.removeInfoPlistDebug = removeInfoPlistDebug;
233
227
  function hasSceneManifest(config) {
234
228
  const infoPlist = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist');
235
229
  if (!(0, fs_extra_1.existsSync)(infoPlist)) {
@@ -297,6 +291,22 @@ function customSceneDelegateClassNames(manifest) {
297
291
  .filter((className) => typeof className === 'string')
298
292
  .filter((className) => className.split('.').pop() !== 'SceneDelegate');
299
293
  }
294
+ async function ensureSPMGitignoreEntry(config) {
295
+ const gitignorePath = (0, path_1.join)(config.ios.nativeProjectDirAbs, 'CapApp-SPM', '.gitignore');
296
+ const entry = '/Package.resolved';
297
+ if (!(0, fs_extra_1.existsSync)(gitignorePath)) {
298
+ log_1.logger.warn(gitignorePath + ' not found, skipping.');
299
+ return;
300
+ }
301
+ const contents = (0, fs_extra_1.readFileSync)(gitignorePath, 'utf-8');
302
+ if (contents.split('\n').some((line) => line.trim() === entry)) {
303
+ log_1.logger.warn('Found ' + entry + ' in ' + gitignorePath + ', skipping.');
304
+ return;
305
+ }
306
+ const updated = contents.endsWith('\n') ? contents + entry + '\n' : contents + '\n' + entry + '\n';
307
+ (0, fs_extra_1.writeFileSync)(gitignorePath, updated);
308
+ }
309
+ exports.ensureSPMGitignoreEntry = ensureSPMGitignoreEntry;
300
310
  async function checkSwiftToolsVersion(config, version) {
301
311
  if (!version) {
302
312
  return null;
@@ -20,7 +20,7 @@ async function getCommandOutput(command, args, options = {}) {
20
20
  try {
21
21
  return (await runCommand(command, args, options)).trim();
22
22
  }
23
- catch (e) {
23
+ catch {
24
24
  return null;
25
25
  }
26
26
  }
@@ -29,7 +29,7 @@ async function isInstalled(command) {
29
29
  try {
30
30
  await (0, utils_subprocess_1.which)(command);
31
31
  }
32
- catch (e) {
32
+ catch {
33
33
  return false;
34
34
  }
35
35
  return true;