@capacitor/cli 9.0.0-alpha.6 → 9.0.0-alpha.8

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.
@@ -0,0 +1,324 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.patchPackageSwiftDeploymentTarget = exports.findCapacitorDependencyVersion = exports.rewriteCapacitorDependency = exports.renderCapacitorPackage = exports.resolveCapacitorPackage = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const path_1 = require("path");
6
+ const semver_1 = require("semver");
7
+ const common_1 = require("../common");
8
+ const errors_1 = require("../errors");
9
+ 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;
12
+ 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';
16
+ const BINARY_PACKAGE_IDENTITY = 'capacitor-swift-pm';
17
+ const ENV_OVERRIDE = 'CAPACITOR_IOS_PACKAGE';
18
+ const REQUIREMENT_KEYS = ['path', 'branch', 'revision', 'exact', 'from'];
19
+ /**
20
+ * Resolves which Capacitor Swift package generated `Package.swift` files should depend on.
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.
29
+ *
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.
34
+ */
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
+ }
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
+ }
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}")`;
64
+ }
65
+ return `.package(url: "${pkg.url}", ${renderRequirement(pkg.requirement)})`;
66
+ }
67
+ exports.renderCapacitorPackage = renderCapacitorPackage;
68
+ /**
69
+ * Repoints an existing `Package.swift` at the resolved Capacitor package.
70
+ *
71
+ * Third-party plugins ship a dependency on `capacitor-swift-pm`. From Capacitor 9 the app depends
72
+ * on the source package instead, and SPM treats the two as separate identities that both vend a
73
+ * `Capacitor` product — so a plugin left untouched would either fail to resolve or link a second
74
+ * copy of the framework. Rewriting keeps the whole graph on one identity.
75
+ */
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;
82
+ }
83
+ exports.rewriteCapacitorDependency = rewriteCapacitorDependency;
84
+ /** Reads the version an existing `Package.swift` pins Capacitor to, if it pins one. */
85
+ function findCapacitorDependencyVersion(content) {
86
+ for (const call of findPackageCalls(content)) {
87
+ if (!referencesCapacitor(call.text)) {
88
+ continue;
89
+ }
90
+ const match = call.text.match(/(?:from|exact):\s*"([^"]+)"/);
91
+ if (match) {
92
+ return match[1];
93
+ }
94
+ }
95
+ return undefined;
96
+ }
97
+ exports.findCapacitorDependencyVersion = findCapacitorDependencyVersion;
98
+ const IOS_PLATFORM_VERSION_REGEX = /\.iOS\(\s*(?:\.v(\d+)|"([\d.]+)")\s*\)/;
99
+ /**
100
+ * Bumps a Package.swift's declared iOS deployment target (e.g. `.iOS(.v13)` or `.iOS("14.0")`) up to
101
+ * `requiredIosVersion` if it's lower.
102
+ *
103
+ * Only relevant for the source package: it declares `platforms: [.iOS(.v16)]` on its own manifest,
104
+ * and SwiftPM enforces that across the whole graph, so a plugin still declaring an older, lower
105
+ * target fails to resolve with "requires minimum platform version X ... but this target supports Y" —
106
+ * even though the very same plugin links fine against the prebuilt `capacitor-swift-pm`, which never
107
+ * declared a `platforms:` entry for SwiftPM to check against.
108
+ */
109
+ function patchPackageSwiftDeploymentTarget(content, requiredIosVersion) {
110
+ const match = content.match(IOS_PLATFORM_VERSION_REGEX);
111
+ if (!match) {
112
+ return { content, changed: false, previousVersion: null };
113
+ }
114
+ const isSymbolic = match[1] !== undefined;
115
+ const previousVersion = isSymbolic ? match[1] : match[2];
116
+ const requiredMajor = Math.trunc(parseFloat(requiredIosVersion));
117
+ if (parseFloat(previousVersion) >= requiredMajor) {
118
+ return { content, changed: false, previousVersion };
119
+ }
120
+ const replacement = isSymbolic ? `.iOS(.v${requiredMajor})` : `.iOS("${requiredMajor}.0")`;
121
+ const patchedContent = content.replace(IOS_PLATFORM_VERSION_REGEX, replacement);
122
+ return { content: patchedContent, changed: true, previousVersion };
123
+ }
124
+ exports.patchPackageSwiftDeploymentTarget = patchPackageSwiftDeploymentTarget;
125
+ function referencesCapacitor(call) {
126
+ return call.includes(BINARY_PACKAGE_IDENTITY) || call.includes(`${SOURCE_PACKAGE_URL}`);
127
+ }
128
+ /**
129
+ * Locates `.package(...)` calls in code, skipping any inside a comment or string literal.
130
+ *
131
+ * Commented-out calls have to be skipped rather than merely tolerated: `replacePackageCalls`
132
+ * keeps the first match and drops the rest, so a commented dependency above the real one would
133
+ * otherwise be the entry that survives.
134
+ */
135
+ function findPackageCalls(content) {
136
+ const marker = '.package(';
137
+ const calls = [];
138
+ for (let index = 0; index < content.length; index++) {
139
+ if (content[index] === '"') {
140
+ index = skipString(content, index);
141
+ continue;
142
+ }
143
+ if (content.startsWith('//', index)) {
144
+ const newline = content.indexOf('\n', index);
145
+ if (newline === -1) {
146
+ break;
147
+ }
148
+ index = newline;
149
+ continue;
150
+ }
151
+ if (content.startsWith('/*', index)) {
152
+ const close = content.indexOf('*/', index + 2);
153
+ if (close === -1) {
154
+ break;
155
+ }
156
+ index = close + 1;
157
+ continue;
158
+ }
159
+ if (!content.startsWith(marker, index)) {
160
+ continue;
161
+ }
162
+ const end = findCallEnd(content, index + marker.length - 1);
163
+ if (end === -1) {
164
+ break;
165
+ }
166
+ calls.push({ start: index, end, text: content.slice(index, end) });
167
+ index = end - 1;
168
+ }
169
+ return calls;
170
+ }
171
+ /** Walks from an opening paren to its match, tracking depth so nested calls don't terminate it. */
172
+ function findCallEnd(content, openParen) {
173
+ let depth = 0;
174
+ for (let cursor = openParen; cursor < content.length; cursor++) {
175
+ const char = content[cursor];
176
+ if (char === '"') {
177
+ cursor = skipString(content, cursor);
178
+ }
179
+ else if (char === '(') {
180
+ depth++;
181
+ }
182
+ else if (char === ')') {
183
+ depth--;
184
+ if (depth === 0) {
185
+ return cursor + 1;
186
+ }
187
+ }
188
+ }
189
+ return -1;
190
+ }
191
+ /** Returns the index of the closing quote of the string literal opening at `open`. */
192
+ function skipString(content, open) {
193
+ for (let cursor = open + 1; cursor < content.length; cursor++) {
194
+ if (content[cursor] === '\\') {
195
+ cursor++;
196
+ }
197
+ else if (content[cursor] === '"') {
198
+ return cursor;
199
+ }
200
+ }
201
+ return content.length;
202
+ }
203
+ /**
204
+ * Points every Capacitor dependency at `rendered`, collapsing them to a single entry.
205
+ *
206
+ * A manifest supporting both Capacitor 8 and 9 can declare the prebuilt and source packages side
207
+ * by side. Both rewrite to the same text, and SPM rejects a manifest that declares one dependency
208
+ * twice, so the extra entries are removed rather than replaced.
209
+ */
210
+ function replacePackageCalls(content, rendered) {
211
+ const matches = findPackageCalls(content).filter((call) => referencesCapacitor(call.text));
212
+ if (matches.length === 0) {
213
+ return content;
214
+ }
215
+ const [survivor, ...duplicates] = matches;
216
+ let result = content;
217
+ // Every duplicate sits after the survivor, so splicing them out backwards leaves its offsets
218
+ // valid and guarantees each one is preceded by the comma separating it from an earlier entry.
219
+ for (const call of duplicates.reverse()) {
220
+ result = result.slice(0, startOfEntry(content, call.start)) + result.slice(call.end);
221
+ }
222
+ return result.slice(0, survivor.start) + rendered + result.slice(survivor.end);
223
+ }
224
+ /**
225
+ * Extends a deletion back over the comma separating an entry from the previous one. Swift allows a
226
+ * trailing comma in an array literal but not a leading one, so the preceding comma is the one to
227
+ * take.
228
+ */
229
+ function startOfEntry(content, start) {
230
+ let cursor = start - 1;
231
+ while (cursor >= 0 && /\s/.test(content[cursor])) {
232
+ cursor--;
233
+ }
234
+ return content[cursor] === ',' ? cursor : start;
235
+ }
236
+ function renderRequirement(requirement) {
237
+ switch (requirement.kind) {
238
+ case 'branch':
239
+ return `branch: "${requirement.branch}"`;
240
+ case 'revision':
241
+ return `revision: "${requirement.revision}"`;
242
+ case 'exact':
243
+ return `exact: "${requirement.version}"`;
244
+ case 'from':
245
+ return `from: "${requirement.version}"`;
246
+ case 'path':
247
+ throw new Error('path requirements are rendered by renderCapacitorPackage');
248
+ }
249
+ }
250
+ function resolveOverride(config) {
251
+ var _a, _b, _c, _d;
252
+ const baseDir = config.app.rootDir;
253
+ const fromEnv = (_a = process.env[ENV_OVERRIDE]) === null || _a === void 0 ? void 0 : _a.trim();
254
+ if (fromEnv) {
255
+ return { requirement: parseRequirementSpec(fromEnv, baseDir) };
256
+ }
257
+ 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;
258
+ if (!fromConfig) {
259
+ return undefined;
260
+ }
261
+ const provided = REQUIREMENT_KEYS.filter((key) => fromConfig[key] !== undefined);
262
+ if (provided.length === 0) {
263
+ (0, errors_1.fatal)(`experimental.ios.spm.capacitorPackage must set one of: ${REQUIREMENT_KEYS.join(', ')}.\n` +
264
+ `Remove the entry to use the version matching the installed @capacitor/ios.`);
265
+ }
266
+ if (provided.length > 1) {
267
+ (0, errors_1.fatal)(`experimental.ios.spm.capacitorPackage sets more than one of: ${provided.join(', ')}.\n` + `Only one may be set.`);
268
+ }
269
+ const key = provided[0];
270
+ const value = String(fromConfig[key]);
271
+ if (key === 'path') {
272
+ if (fromConfig.url !== undefined) {
273
+ (0, errors_1.fatal)(`experimental.ios.spm.capacitorPackage cannot set both "url" and "path".`);
274
+ }
275
+ return { requirement: pathRequirement(value, baseDir) };
276
+ }
277
+ return { url: fromConfig.url, requirement: { kind: key, ...requirementValue(key, value) } };
278
+ }
279
+ function requirementValue(key, value) {
280
+ switch (key) {
281
+ case 'branch':
282
+ return { branch: value };
283
+ case 'revision':
284
+ return { revision: value };
285
+ default:
286
+ return { version: value };
287
+ }
288
+ }
289
+ /**
290
+ * Parses a `CAPACITOR_IOS_PACKAGE` value. Accepts an explicit `kind:value` form, or infers `path`
291
+ * for anything path-shaped and `exact` for a bare version.
292
+ */
293
+ function parseRequirementSpec(spec, baseDir) {
294
+ const separator = spec.indexOf(':');
295
+ if (separator > 0) {
296
+ const key = spec.slice(0, separator);
297
+ const value = spec.slice(separator + 1);
298
+ if (REQUIREMENT_KEYS.includes(key)) {
299
+ if (key === 'path') {
300
+ return pathRequirement(value, baseDir);
301
+ }
302
+ return {
303
+ kind: key,
304
+ ...requirementValue(key, value),
305
+ };
306
+ }
307
+ }
308
+ if (spec.startsWith('.') || (0, path_1.isAbsolute)(spec)) {
309
+ return pathRequirement(spec, baseDir);
310
+ }
311
+ if ((0, semver_1.valid)(spec)) {
312
+ return { kind: 'exact', version: spec };
313
+ }
314
+ return (0, errors_1.fatal)(`Could not understand ${ENV_OVERRIDE}="${spec}".\n` +
315
+ `Expected one of ${REQUIREMENT_KEYS.map((k) => `${k}:<value>`).join(', ')}, a path, or a version.`);
316
+ }
317
+ function pathRequirement(value, baseDir) {
318
+ const absolutePath = (0, path_1.resolve)(baseDir, value);
319
+ if (!(0, fs_extra_1.existsSync)((0, path_1.resolve)(absolutePath, 'Package.swift'))) {
320
+ (0, errors_1.fatal)(`No Package.swift found at ${absolutePath}.\n` +
321
+ `A local Capacitor package must point at the repository root, not the ios directory.`);
322
+ }
323
+ return { kind: 'path', absolutePath };
324
+ }
@@ -3,11 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateCordovaPackageFile = exports.generateCordovaPackageFiles = exports.cordovaPodfileLines = exports.filterARCFiles = exports.removePluginsNativeFiles = exports.copyPluginsNativeFiles = exports.generateCordovaPodspecs = void 0;
4
4
  const fs_extra_1 = require("fs-extra");
5
5
  const path_1 = require("path");
6
- const common_1 = require("../common");
7
6
  const cordova_1 = require("../cordova");
8
- const common_2 = require("../ios/common");
7
+ const common_1 = require("../ios/common");
8
+ const log_1 = require("../log");
9
9
  const plugin_1 = require("../plugin");
10
- const migrate_1 = require("../tasks/migrate");
10
+ const capacitor_package_1 = require("../util/capacitor-package");
11
11
  const template_1 = require("../util/template");
12
12
  const platform = 'ios';
13
13
  async function generateCordovaPodspecs(cordovaPlugins, config) {
@@ -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
  }
@@ -321,10 +325,122 @@ async function generateCordovaPackageFiles(cordovaPlugins, config) {
321
325
  });
322
326
  }
323
327
  exports.generateCordovaPackageFiles = generateCordovaPackageFiles;
328
+ function buildBinaryTargetEntries(p, frameworks) {
329
+ const customXcframeworks = frameworks.filter((f) => f.$.custom === 'true' && f.$.src.endsWith('.xcframework'));
330
+ const customFrameworks = frameworks.filter((f) => f.$.custom === 'true' && f.$.src.endsWith('.framework'));
331
+ if (customFrameworks.length > 0) {
332
+ customFrameworks.forEach((f) => {
333
+ log_1.logger.warn(`${p.id}: custom .framework files are not supported as binaryTarget in SPM (${f.$.src}). Convert to .xcframework for SPM compatibility.`);
334
+ });
335
+ }
336
+ const binaryTargetsText = customXcframeworks
337
+ .map((f) => {
338
+ const name = f.$.src.split('/').pop().replace('.xcframework', '');
339
+ return `,
340
+ .binaryTarget(
341
+ name: "${name}",
342
+ path: "${f.$.src}"
343
+ )`;
344
+ })
345
+ .join('');
346
+ const binaryDepsText = customXcframeworks
347
+ .map((f) => {
348
+ const name = f.$.src.split('/').pop().replace('.xcframework', '');
349
+ return `,\n .target(name: "${name}")`;
350
+ })
351
+ .join('');
352
+ return { binaryTargetsText, binaryDepsText };
353
+ }
354
+ function buildResourcesText(resources) {
355
+ const resourceEntry = [];
356
+ for (const resource of resources) {
357
+ resourceEntry.push(`.copy("resources/${resource.$.src.split('/').pop()}")`);
358
+ }
359
+ return resources.length > 0
360
+ ? `,
361
+ resources: [
362
+ ${resourceEntry.join(',\n ')}
363
+ ]`
364
+ : '';
365
+ }
366
+ async function buildDependencyTexts(p, config) {
367
+ let allDependencies = (0, plugin_1.getPlatformElement)(p, platform, 'dependency');
368
+ if (p.xml['dependency']) {
369
+ allDependencies = allDependencies.concat(p.xml['dependency']);
370
+ }
371
+ let packageText = '';
372
+ let productText = '';
373
+ await Promise.all(allDependencies.map(async (dep) => {
374
+ let plugin = dep.$.id;
375
+ if (plugin.includes('@') && plugin.indexOf('@') !== 0) {
376
+ [plugin] = plugin.split('@');
377
+ }
378
+ const depPlugin = await (0, plugin_1.resolvePlugin)(config, plugin);
379
+ if (depPlugin) {
380
+ const headerFiles = (0, plugin_1.getPlatformElement)(depPlugin, platform, 'header-file');
381
+ const resources = (0, plugin_1.getPlatformElement)(depPlugin, platform, 'resource-file');
382
+ const sourceFiles = (0, plugin_1.getPlatformElement)(depPlugin, platform, 'source-file');
383
+ if (sourceFiles.length === 0 && headerFiles.length === 0 && resources.length === 0) {
384
+ return;
385
+ }
386
+ packageText += `,\n .package(name: "${depPlugin.name}", path: "../${depPlugin.name}")`;
387
+ productText += `,\n .product(name: "${depPlugin.name}", package: "${depPlugin.name}")`;
388
+ }
389
+ }));
390
+ return { packageText, productText };
391
+ }
392
+ function buildCSettingsText(p, sourceFiles) {
393
+ var _a;
394
+ const pluginId = p.id;
395
+ const allFlags = new Set();
396
+ for (const sourceFile of sourceFiles) {
397
+ const flags = (_a = sourceFile.$) === null || _a === void 0 ? void 0 : _a['compiler-flags'];
398
+ if (flags) {
399
+ flags
400
+ .split(/\s+/)
401
+ .map((f) => f.trim())
402
+ .filter((f) => f.length > 0)
403
+ .forEach((f) => allFlags.add(f));
404
+ }
405
+ }
406
+ if (allFlags.size === 0) {
407
+ return '';
408
+ }
409
+ const entries = [];
410
+ const unsupportedFlags = [];
411
+ for (const flag of allFlags) {
412
+ if (flag.startsWith('-D')) {
413
+ const definition = flag.slice(2);
414
+ const eqIndex = definition.indexOf('=');
415
+ if (eqIndex !== -1) {
416
+ const name = definition.slice(0, eqIndex);
417
+ const value = definition.slice(eqIndex + 1);
418
+ entries.push(` .define("${name}", to: "${value}")`);
419
+ }
420
+ else {
421
+ entries.push(` .define("${definition}")`);
422
+ }
423
+ }
424
+ else {
425
+ unsupportedFlags.push(flag);
426
+ }
427
+ }
428
+ if (unsupportedFlags.length > 0) {
429
+ log_1.logger.warn(`${pluginId}: the following compiler flags are not supported in SPM and were ignored: ${unsupportedFlags.join(', ')}. ` +
430
+ `This might cause the plugin to fail to compile.`);
431
+ }
432
+ if (entries.length === 0) {
433
+ return '';
434
+ }
435
+ return `,
436
+ cSettings: [
437
+ ${entries.join(',\n')}
438
+ ]`;
439
+ }
324
440
  async function generateCordovaPackageFile(p, config) {
325
441
  var _a;
326
- const iosPlatformVersion = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name);
327
- const iosVersion = (0, common_2.getMajoriOSVersion)(config);
442
+ const capacitorPackage = await (0, capacitor_package_1.resolveCapacitorPackage)(config, 'from');
443
+ const iosVersion = (0, common_1.getMajoriOSVersion)(config);
328
444
  const headerFiles = (0, plugin_1.getPlatformElement)(p, platform, 'header-file');
329
445
  let headersText = '';
330
446
  if (headerFiles.length > 0) {
@@ -335,11 +451,34 @@ async function generateCordovaPackageFile(p, config) {
335
451
  if ((_a = platformTag.$) === null || _a === void 0 ? void 0 : _a.package) {
336
452
  const packageSwiftPath = (0, path_1.join)(p.rootPath, 'Package.swift');
337
453
  let content = await (0, fs_extra_1.readFile)(packageSwiftPath, { encoding: 'utf-8' });
338
- content = content.replace(`apache`, `ionic-team`).replaceAll(`cordova-ios`, `capacitor-swift-pm`);
339
- content = (0, migrate_1.setAllStringIn)(content, `url: "https://github.com/ionic-team/capacitor-swift-pm.git",`, `)`, ` from: "${iosPlatformVersion}"`);
454
+ content = content.replace(`apache`, `ionic-team`).replaceAll(`cordova-ios`, capacitorPackage.identity);
455
+ content = (0, capacitor_package_1.rewriteCapacitorDependency)(content, capacitorPackage, p.rootPath);
456
+ if (capacitorPackage.sourceBased) {
457
+ content = (0, capacitor_package_1.patchPackageSwiftDeploymentTarget)(content, iosVersion).content;
458
+ }
340
459
  await (0, fs_extra_1.writeFile)(packageSwiftPath, content);
341
460
  }
342
461
  else {
462
+ const resources = (0, plugin_1.getPlatformElement)(p, platform, 'resource-file');
463
+ const sourceFiles = (0, plugin_1.getPlatformElement)(p, platform, 'source-file');
464
+ if (sourceFiles.length === 0 && headerFiles.length === 0 && resources.length === 0) {
465
+ return;
466
+ }
467
+ const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework');
468
+ const { binaryTargetsText, binaryDepsText } = buildBinaryTargetEntries(p, frameworks);
469
+ const cSettingsText = buildCSettingsText(p, sourceFiles);
470
+ const systemFrameworks = frameworks.filter((f) => !f.$.custom && f.$.src.endsWith('.framework'));
471
+ const hasWeakFrameworks = systemFrameworks.some((f) => f.$.weak === 'true');
472
+ const requiredSystemFrameworks = systemFrameworks.filter((f) => f.$.weak !== 'true');
473
+ const resourcesText = buildResourcesText(resources);
474
+ const libraryTypeText = hasWeakFrameworks ? `\n type: .dynamic,` : '';
475
+ const linkerSettingsText = requiredSystemFrameworks.length > 0
476
+ ? `,
477
+ linkerSettings: [
478
+ ${requiredSystemFrameworks.map((f) => ` .linkedFramework("${f.$.src.replace('.framework', '')}")`).join(',\n')}
479
+ ]`
480
+ : '';
481
+ const { packageText, productText } = await buildDependencyTexts(p, config);
343
482
  const content = `// swift-tools-version: 5.9
344
483
 
345
484
  import PackageDescription
@@ -349,21 +488,21 @@ let package = Package(
349
488
  platforms: [.iOS(.v${iosVersion})],
350
489
  products: [
351
490
  .library(
352
- name: "${p.name}",
491
+ name: "${p.name}",${libraryTypeText}
353
492
  targets: ["${p.name}"]
354
493
  )
355
494
  ],
356
495
  dependencies: [
357
- .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "${iosPlatformVersion}")
496
+ ${(0, capacitor_package_1.renderCapacitorPackage)(capacitorPackage, (0, path_1.join)(config.ios.cordovaPluginsDirAbs, 'sources', p.name))}${packageText}
358
497
  ],
359
498
  targets: [
360
499
  .target(
361
500
  name: "${p.name}",
362
501
  dependencies: [
363
- .product(name: "Cordova", package: "capacitor-swift-pm")
502
+ .product(name: "Cordova", package: "${capacitorPackage.identity}")${binaryDepsText}${productText}
364
503
  ],
365
- path: "."${headersText}
366
- )
504
+ path: "."${resourcesText}${headersText}${cSettingsText}${linkerSettingsText}
505
+ )${binaryTargetsText}
367
506
  ]
368
507
  )`;
369
508
  await (0, fs_extra_1.writeFile)((0, path_1.join)(config.ios.cordovaPluginsDirAbs, 'sources', p.name, 'Package.swift'), content);
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
@@ -4,11 +4,45 @@ 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) => {
28
+ const requireTS = async (ts, p) => {
11
29
  const id = (0, path_1.resolve)(p);
30
+ if (!hasClassicCompilerAPI(ts)) {
31
+ // Node has its own built-in TypeScript syntax stripping (stable since Node 23.6, and
32
+ // available behind --experimental-strip-types since Node 22.6), so we can load the file
33
+ // directly via the native ESM loader instead of transpiling it ourselves.
34
+ try {
35
+ return await dynamicImport((0, url_1.pathToFileURL)(id).href);
36
+ }
37
+ catch (e) {
38
+ if ((e === null || e === void 0 ? void 0 : e.code) === 'ERR_UNKNOWN_FILE_EXTENSION') {
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
+ `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.', { cause: e });
42
+ }
43
+ throw e;
44
+ }
45
+ }
12
46
  delete require.cache[id];
13
47
  require.extensions['.ts'] = (module, fileName) => {
14
48
  var _a;
@@ -34,7 +68,7 @@ const requireTS = (ts, p) => {
34
68
  }
35
69
  (_a = module._compile) === null || _a === void 0 ? void 0 : _a.call(module, sourceText, fileName);
36
70
  };
37
- 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
38
72
  delete require.extensions['.ts'];
39
73
  return m;
40
74
  };
@@ -43,7 +77,7 @@ function resolveNode(root, ...pathSegments) {
43
77
  try {
44
78
  return require.resolve(pathSegments.join('/'), { paths: [root] });
45
79
  }
46
- catch (e) {
80
+ catch {
47
81
  const path = [root, 'node_modules', ...pathSegments].join('/');
48
82
  if ((0, fs_1.existsSync)(path)) {
49
83
  return path;