react-native 0.88.0-rc.0 → 0.88.0-rc.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.
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Renderer/implementations/ReactFabric-dev.js +3056 -1531
- package/Libraries/Renderer/implementations/ReactFabric-prod.js +2239 -1011
- package/Libraries/Renderer/implementations/ReactFabric-profiling.js +2451 -1124
- package/React/Base/RCTVersion.m +1 -1
- package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +8 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +7 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +11 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +3 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +3 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +12 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Canary_Android.kt +3 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +3 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +15 -1
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +4 -1
- package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +5 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +6 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +74 -56
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +4 -2
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +5 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +10 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSCanary.h +5 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +2 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +6 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +3 -1
- package/package.json +10 -10
- package/scripts/codegen/generate-artifacts-executor/generateRCTThirdPartyComponents.js +18 -4
- package/scripts/setup-apple-spm.js +82 -4
- package/scripts/spm/autolinking-plugins.js +8 -5
- package/scripts/spm/expand-spm-dependencies.js +217 -156
- package/scripts/spm/generate-spm-autolinking.js +114 -88
- package/scripts/spm/generate-spm-xcodeproj.js +67 -22
- package/scripts/spm/ios-deployment-target.js +378 -0
- package/scripts/spm/read-podspec.js +156 -8
- package/scripts/spm/scaffold-package-swift.js +272 -105
- package/scripts/spm/spm-pbxproj.js +36 -21
- package/scripts/spm/spm-types.js +25 -8
- package/scripts/spm/spm-utils.js +26 -0
- package/scripts/spm/swiftpm-config.js +245 -0
- package/scripts/spm/sync-spm-autolinking.js +11 -2
- package/sdks/hermes-engine/version.properties +1 -1
- package/src/private/featureflags/ReactNativeFeatureFlags.js +10 -5
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +2 -1
- package/src/private/webapis/dom/nodes/ReactNativeElement.js +6 -4
- package/src/private/webapis/dom/nodes/ReadOnlyText.js +6 -4
- package/src/react-private-interface.js +4 -0
- package/src/react-private-interface.js.flow +2 -0
- package/types_generated/Libraries/ReactNative/FabricUIManager.d.ts +47 -0
- package/types_generated/src/react-private-interface.d.ts +4 -1
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
/*:: import type {
|
|
13
|
+
/*:: import type {SwiftpmConfig} from './swiftpm-config';
|
|
14
|
+
import type {
|
|
14
15
|
AggregatorInput,
|
|
15
16
|
AutolinkedDep,
|
|
16
17
|
AutolinkingArgs,
|
|
@@ -62,11 +63,15 @@ const {
|
|
|
62
63
|
SpmNameCollisionError,
|
|
63
64
|
assertSwiftNameNotReserved,
|
|
64
65
|
defaultReadConfig,
|
|
66
|
+
defaultReadPodspec,
|
|
65
67
|
defaultResolveDep,
|
|
66
68
|
expandSpmDependencies,
|
|
67
|
-
isValidSwiftName,
|
|
68
69
|
} = require('./expand-spm-dependencies');
|
|
69
|
-
const {
|
|
70
|
+
const {
|
|
71
|
+
MIN_IOS_VERSION_SUPPORTED,
|
|
72
|
+
sanitizeIosDeploymentTarget,
|
|
73
|
+
} = require('./ios-deployment-target');
|
|
74
|
+
const {findPodspecs, readPodspecCached} = require('./read-podspec');
|
|
70
75
|
const {
|
|
71
76
|
AUTOLINKED_PACKAGE_NAME,
|
|
72
77
|
REACT_CODEGEN_PACKAGE_NAME,
|
|
@@ -74,10 +79,14 @@ const {
|
|
|
74
79
|
REACT_NATIVE_PACKAGE_NAME,
|
|
75
80
|
REACT_NATIVE_PRODUCTS,
|
|
76
81
|
RemoteVersionError,
|
|
82
|
+
displayPath,
|
|
77
83
|
findProjectRoot,
|
|
84
|
+
isValidSwiftName,
|
|
78
85
|
makeLogger,
|
|
79
86
|
remotePackageConfig,
|
|
87
|
+
swiftNameKey,
|
|
80
88
|
} = require('./spm-utils');
|
|
89
|
+
const {readSwiftpmConfig, stringList} = require('./swiftpm-config');
|
|
81
90
|
const fs = require('node:fs');
|
|
82
91
|
const path = require('node:path');
|
|
83
92
|
const yargs = require('yargs');
|
|
@@ -205,6 +214,10 @@ function parseArgs(argv /*: Array<string> */) /*: AutolinkingArgs */ {
|
|
|
205
214
|
describe:
|
|
206
215
|
'Path to the xcframeworks sub-package (absolute or relative to appRoot)',
|
|
207
216
|
})
|
|
217
|
+
.option('ios-deployment-target', {
|
|
218
|
+
type: 'string',
|
|
219
|
+
describe: `Platform floor of the generated manifests (default: ${MIN_IOS_VERSION_SUPPORTED})`,
|
|
220
|
+
})
|
|
208
221
|
.usage(
|
|
209
222
|
'Usage: $0 [options]\n\nGenerates autolinked/Package.swift for SPM autolinking.',
|
|
210
223
|
)
|
|
@@ -217,6 +230,9 @@ function parseArgs(argv /*: Array<string> */) /*: AutolinkingArgs */ {
|
|
|
217
230
|
autolinkingJson: parsed['autolinking-json'] ?? null,
|
|
218
231
|
output: parsed.output ?? null,
|
|
219
232
|
xcframeworksPath: parsed['xcframeworks-path'] ?? null,
|
|
233
|
+
iosDeploymentTarget: sanitizeIosDeploymentTarget(
|
|
234
|
+
parsed['ios-deployment-target'],
|
|
235
|
+
),
|
|
220
236
|
};
|
|
221
237
|
}
|
|
222
238
|
|
|
@@ -233,92 +249,116 @@ function readAutolinkingJson(
|
|
|
233
249
|
}
|
|
234
250
|
|
|
235
251
|
/**
|
|
236
|
-
*
|
|
237
|
-
*
|
|
252
|
+
* One of the app's settings, and the root that declared it. Looked up field by
|
|
253
|
+
* field so a project-root `swiftpmConfig` cannot hide a field the Xcode dir
|
|
254
|
+
* still declares: the directory holding the app's package.json wins (where
|
|
255
|
+
* codegen reads `codegenConfig` from), and `appRoot` — the Xcode project dir,
|
|
256
|
+
* the settings' old home — fills the gaps.
|
|
257
|
+
*/
|
|
258
|
+
function appConfigField(
|
|
259
|
+
appRoot /*: string */,
|
|
260
|
+
field /*: 'modules' | 'denyPlugins' */,
|
|
261
|
+
) /*: ?{root: string, value: unknown} */ {
|
|
262
|
+
const projectRoot = findProjectRoot(appRoot);
|
|
263
|
+
const roots = projectRoot === appRoot ? [appRoot] : [projectRoot, appRoot];
|
|
264
|
+
for (const root of roots) {
|
|
265
|
+
const value = readSwiftpmConfig(root, defaultReadConfig(root))?.[field];
|
|
266
|
+
if (value === undefined) {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (root !== projectRoot) {
|
|
270
|
+
warn(
|
|
271
|
+
`Read '${field}' from ${displayPath(root)}. Move it to 'swiftpmConfig' in ${displayPath(path.join(projectRoot, 'package.json'))} — an app's SwiftPM settings belong with its package.json.`,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
return {root, value};
|
|
275
|
+
}
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* The app's own native modules — the ones autolinking.json cannot discover —
|
|
281
|
+
* with the root that declared them, since each `path` is relative to the file
|
|
282
|
+
* it is written in:
|
|
238
283
|
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
* spm: {
|
|
243
|
-
* modules: [
|
|
284
|
+
* // <project root>/package.json
|
|
285
|
+
* "swiftpmConfig": {
|
|
286
|
+
* "modules": [
|
|
244
287
|
* {
|
|
245
|
-
* name: "MyNativeModule",
|
|
246
|
-
* path: "ios/MyNativeModule",
|
|
247
|
-
* exclude: ["*.js", "*.podspec"]
|
|
288
|
+
* "name": "MyNativeModule",
|
|
289
|
+
* "path": "ios/MyNativeModule",
|
|
290
|
+
* "exclude": ["*.js", "*.podspec"]
|
|
248
291
|
* }
|
|
249
292
|
* ]
|
|
250
293
|
* }
|
|
251
|
-
* }
|
|
252
294
|
*/
|
|
253
295
|
function readSpmModulesFromConfig(
|
|
254
296
|
appRoot /*: string */,
|
|
255
|
-
) /*: Array<SpmModuleConfig
|
|
256
|
-
const
|
|
257
|
-
if (!
|
|
258
|
-
return [];
|
|
297
|
+
) /*: {modules: Array<SpmModuleConfig>, root: string} */ {
|
|
298
|
+
const declared = appConfigField(appRoot, 'modules');
|
|
299
|
+
if (declared == null || !Array.isArray(declared.value)) {
|
|
300
|
+
return {modules: [], root: appRoot};
|
|
259
301
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
302
|
+
// Entries stay unvalidated here: assertSpmModuleName checks each name, and
|
|
303
|
+
// the emission loop reads the rest defensively.
|
|
304
|
+
// $FlowFixMe[incompatible-type] user-authored entries
|
|
305
|
+
const modules /*: ReadonlyArray<SpmModuleConfig> */ = declared.value;
|
|
306
|
+
return {modules: [...modules], root: declared.root};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function moduleClashDiagnosis(
|
|
310
|
+
moduleName /*: string */,
|
|
311
|
+
clash /*: string */,
|
|
312
|
+
) /*: string */ {
|
|
313
|
+
if (clash === moduleName) {
|
|
314
|
+
return `is already the name of another autolinked target.`;
|
|
267
315
|
}
|
|
316
|
+
if (clash.toLowerCase() === moduleName.toLowerCase()) {
|
|
317
|
+
return `differs from the existing target '${clash}' only in case, which collides on case-insensitive filesystems.`;
|
|
318
|
+
}
|
|
319
|
+
return `compiles as the same module as the existing target '${clash}'.`;
|
|
268
320
|
}
|
|
269
321
|
|
|
270
322
|
/**
|
|
271
323
|
* Validates one app-local `spm.modules` name against the same rules a library's
|
|
272
324
|
* `spm.name` gets: a usable Swift identifier, not a name React Native reserves,
|
|
273
325
|
* and not one already taken by another module or an autolinked dep.
|
|
274
|
-
* `taken`
|
|
326
|
+
* `taken` is keyed by swiftNameKey, valued with the name as written.
|
|
275
327
|
*/
|
|
276
328
|
function assertSpmModuleName(
|
|
277
329
|
name /*: unknown */,
|
|
278
330
|
taken /*: Map<string, string> */,
|
|
279
331
|
) /*: void */ {
|
|
280
332
|
const remedy =
|
|
281
|
-
"Rename it in this app's
|
|
333
|
+
"Rename it in this app's package.json 'swiftpmConfig.modules'.";
|
|
282
334
|
if (typeof name !== 'string' || !isValidSwiftName(name)) {
|
|
283
335
|
throw new Error(
|
|
284
|
-
`react-native autolinking: invalid '
|
|
336
|
+
`react-native autolinking: invalid 'swiftpmConfig.modules' name ${JSON.stringify(name) ?? 'undefined'}: must start with a letter or underscore and contain only letters, digits, underscores, or hyphens.`,
|
|
285
337
|
);
|
|
286
338
|
}
|
|
287
339
|
const moduleName = name;
|
|
288
340
|
assertSwiftNameNotReserved(moduleName, {
|
|
289
|
-
label: `the '
|
|
341
|
+
label: `the 'swiftpmConfig.modules' entry '${moduleName}'`,
|
|
290
342
|
remedy,
|
|
291
343
|
extraReservedNames: reservedNamesForRun(),
|
|
292
344
|
});
|
|
293
|
-
const clash = taken.get(moduleName
|
|
345
|
+
const clash = taken.get(swiftNameKey(moduleName));
|
|
294
346
|
if (clash != null) {
|
|
295
347
|
throw new SpmNameCollisionError(
|
|
296
|
-
`react-native autolinking: SPM Swift name collision: the '
|
|
297
|
-
(clash
|
|
298
|
-
? `is already the name of another autolinked target.`
|
|
299
|
-
: `differs from the existing target '${clash}' only in case, which collides on case-insensitive filesystems.`) +
|
|
348
|
+
`react-native autolinking: SPM Swift name collision: the 'swiftpmConfig.modules' entry '${moduleName}' ` +
|
|
349
|
+
moduleClashDiagnosis(moduleName, clash) +
|
|
300
350
|
` ${remedy}`,
|
|
301
351
|
);
|
|
302
352
|
}
|
|
303
353
|
}
|
|
304
354
|
|
|
305
355
|
/**
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
356
|
+
* The app's `denyPlugins` — npm names of autolinking plugins to skip. The
|
|
357
|
+
* escape hatch for transitive plugin discovery (an app opts a framework's
|
|
358
|
+
* plugin OUT); no allowlist is required.
|
|
309
359
|
*/
|
|
310
360
|
function readDenyPluginsFromConfig(appRoot /*: string */) /*: Array<string> */ {
|
|
311
|
-
|
|
312
|
-
if (!fs.existsSync(configPath)) {
|
|
313
|
-
return [];
|
|
314
|
-
}
|
|
315
|
-
try {
|
|
316
|
-
// $FlowFixMe[unsupported-syntax] dynamic require by computed path
|
|
317
|
-
const config = require(configPath);
|
|
318
|
-
return config.spm?.denyPlugins ?? [];
|
|
319
|
-
} catch (e) {
|
|
320
|
-
return [];
|
|
321
|
-
}
|
|
361
|
+
return stringList(appConfigField(appRoot, 'denyPlugins')?.value);
|
|
322
362
|
}
|
|
323
363
|
|
|
324
364
|
/**
|
|
@@ -433,21 +473,9 @@ function findSelfManagedPackageDir(absSource /*: string */) /*: ?string */ {
|
|
|
433
473
|
* the scaffolder translates the podspec into a Package.swift.
|
|
434
474
|
*/
|
|
435
475
|
function hasPodspec(absSource /*: string */) /*: boolean */ {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
if (
|
|
440
|
-
fs
|
|
441
|
-
.readdirSync(dir)
|
|
442
|
-
.some(e => e.endsWith('.podspec') && !e.startsWith('.spm-scaffold-'))
|
|
443
|
-
) {
|
|
444
|
-
return true;
|
|
445
|
-
}
|
|
446
|
-
} catch {
|
|
447
|
-
// dir does not exist; try the next candidate
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return false;
|
|
476
|
+
return [absSource, path.join(absSource, 'ios')].some(
|
|
477
|
+
dir => findPodspecs(dir).length > 0,
|
|
478
|
+
);
|
|
451
479
|
}
|
|
452
480
|
|
|
453
481
|
/**
|
|
@@ -778,9 +806,9 @@ function expandSpmSourceGlobs(
|
|
|
778
806
|
* Returns null if the dependency doesn't have iOS support.
|
|
779
807
|
*
|
|
780
808
|
* `swiftNameByNpm` maps each autolinked dep's npm name to its resolved Swift
|
|
781
|
-
* name (populated by expandSpmDependencies
|
|
782
|
-
*
|
|
783
|
-
*
|
|
809
|
+
* name (populated by expandSpmDependencies from the dep's podspec and
|
|
810
|
+
* `spm.name`). Every name this function emits comes from there — see
|
|
811
|
+
* requireSwiftName.
|
|
784
812
|
*/
|
|
785
813
|
/**
|
|
786
814
|
* Read the dep's podspec (if any) and extract its declared
|
|
@@ -799,24 +827,12 @@ function expandSpmSourceGlobs(
|
|
|
799
827
|
function extractPodspecHeaderSearchPaths(
|
|
800
828
|
sourceDir /*: string */,
|
|
801
829
|
) /*: Array<string> */ {
|
|
802
|
-
|
|
803
|
-
try {
|
|
804
|
-
const entries = fs.readdirSync(sourceDir);
|
|
805
|
-
// Skip a crashed run's leftover `.spm-scaffold-<pid>-<name>.podspec` copy.
|
|
806
|
-
const candidate = entries.find(
|
|
807
|
-
e => e.endsWith('.podspec') && !e.startsWith('.spm-scaffold-'),
|
|
808
|
-
);
|
|
809
|
-
if (candidate != null) {
|
|
810
|
-
podspecPath = path.join(sourceDir, candidate);
|
|
811
|
-
}
|
|
812
|
-
} catch {
|
|
813
|
-
return [];
|
|
814
|
-
}
|
|
830
|
+
const podspecPath /*: ?string */ = findPodspecs(sourceDir)[0];
|
|
815
831
|
if (podspecPath == null) return [];
|
|
816
832
|
|
|
817
833
|
let model;
|
|
818
834
|
try {
|
|
819
|
-
model =
|
|
835
|
+
model = readPodspecCached(podspecPath);
|
|
820
836
|
} catch {
|
|
821
837
|
return [];
|
|
822
838
|
}
|
|
@@ -936,6 +952,8 @@ function generateAutolinkedPackageSwift(
|
|
|
936
952
|
input.pluginPackageDeps ?? [];
|
|
937
953
|
const pluginProductDeps /*: ReadonlyArray<PluginProductDep> */ =
|
|
938
954
|
input.pluginProductDeps ?? [];
|
|
955
|
+
const iosDeploymentTarget /*: string */ =
|
|
956
|
+
input.iosDeploymentTarget ?? MIN_IOS_VERSION_SUPPORTED;
|
|
939
957
|
|
|
940
958
|
// Package-level dependencies: one .package(path:) per autolinked dep,
|
|
941
959
|
// plus ReactNative if any inline target needs to import React headers.
|
|
@@ -1069,7 +1087,7 @@ import Foundation
|
|
|
1069
1087
|
|
|
1070
1088
|
${guardBlock}let package = Package(
|
|
1071
1089
|
name: "${AUTOLINKED_PACKAGE_NAME}",
|
|
1072
|
-
platforms: [.iOS(
|
|
1090
|
+
platforms: [.iOS("${iosDeploymentTarget}")],
|
|
1073
1091
|
products: [
|
|
1074
1092
|
.library(name: "${AUTOLINKED_PACKAGE_NAME}", targets: ["AutolinkedAggregate"]),
|
|
1075
1093
|
],
|
|
@@ -1119,6 +1137,8 @@ function generateSynthPackageSwift(spec /*: SynthPackageSpec */) /*: string */ {
|
|
|
1119
1137
|
const targetPath /*: string */ = spec.targetPath ?? `Sources/${swiftName}`;
|
|
1120
1138
|
const siblingSynthAbsolutePaths /*: {[string]: string} */ =
|
|
1121
1139
|
spec.siblingSynthAbsolutePaths ?? {};
|
|
1140
|
+
const iosDeploymentTarget /*: string */ =
|
|
1141
|
+
spec.iosDeploymentTarget ?? MIN_IOS_VERSION_SUPPORTED;
|
|
1122
1142
|
|
|
1123
1143
|
// Package dependencies — ReactNative + each spm sibling synth package.
|
|
1124
1144
|
// The React + codegen package paths are plain relative strings computed by
|
|
@@ -1217,7 +1237,7 @@ import PackageDescription
|
|
|
1217
1237
|
|
|
1218
1238
|
let package = Package(
|
|
1219
1239
|
name: "${swiftName}",
|
|
1220
|
-
platforms: [.iOS(
|
|
1240
|
+
platforms: [.iOS("${iosDeploymentTarget}")],
|
|
1221
1241
|
products: [
|
|
1222
1242
|
.library(name: "${swiftName}"${isDynamic ? ', type: .dynamic' : ''}, targets: ["${swiftName}"]),
|
|
1223
1243
|
],
|
|
@@ -1312,8 +1332,8 @@ function main(argv /*:: ?: Array<string> */) /*: void */ {
|
|
|
1312
1332
|
const allDeps = expandSpmDependencies(directDeps, {
|
|
1313
1333
|
readConfig: defaultReadConfig,
|
|
1314
1334
|
resolveDep: defaultResolveDep,
|
|
1335
|
+
readPodspec: defaultReadPodspec,
|
|
1315
1336
|
extraReservedNames: reservedNamesForRun(),
|
|
1316
|
-
log,
|
|
1317
1337
|
});
|
|
1318
1338
|
|
|
1319
1339
|
// Map every autolinked npm name to its resolved Swift name so transitive
|
|
@@ -1380,7 +1400,7 @@ function main(argv /*:: ?: Array<string> */) /*: void */ {
|
|
|
1380
1400
|
const dependents = pluginHostDependents.get(dep.name);
|
|
1381
1401
|
if (dependents != null) {
|
|
1382
1402
|
throw new Error(
|
|
1383
|
-
`react-native autolinking: '${dep.name}' ships an SPM autolinking plugin, which owns its native contribution — so React Native does not build it as a sibling target for anything to depend on. It is declared
|
|
1403
|
+
`react-native autolinking: '${dep.name}' ships an SPM autolinking plugin, which owns its native contribution — so React Native does not build it as a sibling target for anything to depend on. It is declared as a SwiftPM dependency by ${dependents.map(name => `'${name}'`).join(', ')}. Remove it there; nothing is lost. Its plugin links its products into the app and resolves its own ecosystem's dependencies, so a library that builds against it does not declare it here.`,
|
|
1384
1404
|
);
|
|
1385
1405
|
}
|
|
1386
1406
|
log(
|
|
@@ -1414,17 +1434,20 @@ function main(argv /*:: ?: Array<string> */) /*: void */ {
|
|
|
1414
1434
|
// If the module declares `sources: [glob, ...]` (CocoaPods-style), expand
|
|
1415
1435
|
// the globs now relative to its dir and attach the file list to the target
|
|
1416
1436
|
// so the emission loop below renders `sources: [...]` literally.
|
|
1417
|
-
const configModules =
|
|
1437
|
+
const {modules: configModules, root: configModulesRoot} =
|
|
1438
|
+
readSpmModulesFromConfig(appRoot);
|
|
1418
1439
|
// Module names land in the manifest exactly as written, so they get the same
|
|
1419
1440
|
// checks a dep's Swift name gets. Seeded with the dep target names already
|
|
1420
1441
|
// emitted so a module can't shadow an autolinked library either.
|
|
1421
1442
|
const takenSwiftNames /*: Map<string, string> */ = new Map(
|
|
1422
|
-
entries.map(entry => [entry.target.name
|
|
1443
|
+
entries.map(entry => [swiftNameKey(entry.target.name), entry.target.name]),
|
|
1423
1444
|
);
|
|
1424
1445
|
for (const mod of configModules) {
|
|
1425
1446
|
assertSpmModuleName(mod.name, takenSwiftNames);
|
|
1426
|
-
takenSwiftNames.set(mod.name
|
|
1427
|
-
|
|
1447
|
+
takenSwiftNames.set(swiftNameKey(mod.name), mod.name);
|
|
1448
|
+
// Relative to the package.json (or config file) that declared it, so a
|
|
1449
|
+
// path reads correctly from where it is written.
|
|
1450
|
+
const absPath = path.resolve(configModulesRoot, mod.path);
|
|
1428
1451
|
const relPath = path.relative(outputDir, absPath);
|
|
1429
1452
|
const userSources =
|
|
1430
1453
|
Array.isArray(mod.sources) && mod.sources.length > 0
|
|
@@ -1689,6 +1712,7 @@ function main(argv /*:: ?: Array<string> */) /*: void */ {
|
|
|
1689
1712
|
|
|
1690
1713
|
const synthContent = generateSynthPackageSwift({
|
|
1691
1714
|
swiftName: target.name,
|
|
1715
|
+
iosDeploymentTarget: args.iosDeploymentTarget,
|
|
1692
1716
|
exclude: prefixedExclude,
|
|
1693
1717
|
sources: prefixedSources,
|
|
1694
1718
|
// Stub include/ subdir lives in the wrapper dir; satisfies SPM's
|
|
@@ -1863,6 +1887,7 @@ function main(argv /*:: ?: Array<string> */) /*: void */ {
|
|
|
1863
1887
|
// autolinked dep is a real SPM package in its own source dir.
|
|
1864
1888
|
const aggregatorContent = generateAutolinkedPackageSwift({
|
|
1865
1889
|
npmDeps: aggregatorPackageDeps,
|
|
1890
|
+
iosDeploymentTarget: args.iosDeploymentTarget,
|
|
1866
1891
|
hasReactDep,
|
|
1867
1892
|
xcframeworksRelPath,
|
|
1868
1893
|
pluginPackageDeps,
|
|
@@ -1999,6 +2024,7 @@ module.exports = {
|
|
|
1999
2024
|
findSelfManagedPackageDir,
|
|
2000
2025
|
hasPodspec,
|
|
2001
2026
|
hasMixedLanguageSources,
|
|
2027
|
+
readDenyPluginsFromConfig,
|
|
2002
2028
|
MissingManifestError,
|
|
2003
2029
|
reportMissingManifests,
|
|
2004
2030
|
AUTOGEN_MARKER,
|
|
@@ -319,7 +319,11 @@ function shellScriptPhase(
|
|
|
319
319
|
outputFileListPaths: empty,
|
|
320
320
|
outputPaths: pathList(options.outputPaths),
|
|
321
321
|
runOnlyForDeploymentPostprocessing: '0',
|
|
322
|
-
|
|
322
|
+
// React Native's own bodies here start with `set -euo pipefail`, which
|
|
323
|
+
// /bin/sh rejects on a host where it isn't bash (e.g. dash's `set -o
|
|
324
|
+
// pipefail: Illegal option`). Run every phase under bash, including
|
|
325
|
+
// plugin-contributed ones, so a plugin's body can rely on it too.
|
|
326
|
+
shellPath: '/bin/bash',
|
|
323
327
|
shellScript: quoteIfNeeded(script),
|
|
324
328
|
},
|
|
325
329
|
};
|
|
@@ -899,7 +903,8 @@ function generateXcscheme(
|
|
|
899
903
|
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
|
900
904
|
<ActionContent
|
|
901
905
|
title = "Sync SPM Autolinking"
|
|
902
|
-
scriptText = "${escapedSync}"
|
|
906
|
+
scriptText = "${escapedSync}"
|
|
907
|
+
shellToInvoke = "/bin/bash">
|
|
903
908
|
<EnvironmentBuildable>
|
|
904
909
|
<BuildableReference
|
|
905
910
|
BuildableIdentifier = "primary"
|
|
@@ -1361,27 +1366,29 @@ function injectSpmIntoPbxproj(
|
|
|
1361
1366
|
// bundles JS via its own phase.
|
|
1362
1367
|
const syncScript = buildSyncAutolinkingScript(reactNativePath);
|
|
1363
1368
|
const syncPhaseUuid = mkUuid('PBXShellScriptBuildPhase', 'SyncAutolinking');
|
|
1369
|
+
const syncEntry = shellScriptPhase(
|
|
1370
|
+
syncPhaseUuid,
|
|
1371
|
+
'Sync SPM Autolinking',
|
|
1372
|
+
syncScript,
|
|
1373
|
+
);
|
|
1364
1374
|
if (!text.includes(syncPhaseUuid)) {
|
|
1365
1375
|
text = insertObjectsIntoSection(
|
|
1366
1376
|
text,
|
|
1367
1377
|
'PBXShellScriptBuildPhase',
|
|
1368
|
-
serializeEntry(
|
|
1369
|
-
shellScriptPhase(syncPhaseUuid, 'Sync SPM Autolinking', syncScript),
|
|
1370
|
-
),
|
|
1378
|
+
serializeEntry(syncEntry),
|
|
1371
1379
|
);
|
|
1372
1380
|
} else {
|
|
1373
|
-
// Already injected on a prior run — the phase object owns
|
|
1374
|
-
//
|
|
1375
|
-
//
|
|
1376
|
-
//
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
);
|
|
1381
|
+
// Already injected on a prior run — the phase object owns these fields,
|
|
1382
|
+
// so refresh them in place (same quoting used at creation) in case the
|
|
1383
|
+
// generated script changed, or a project injected before shellPath moved
|
|
1384
|
+
// to bash (see shellScriptPhase) still has the stale value. Byte-identical
|
|
1385
|
+
// when neither did; field order and every other byte of the phase are
|
|
1386
|
+
// untouched.
|
|
1387
|
+
for (const key of ['shellScript', 'shellPath']) {
|
|
1388
|
+
const current = findObjectByUuid(text, syncPhaseUuid);
|
|
1389
|
+
if (current != null) {
|
|
1390
|
+
text = setScalarField(text, current, key, syncEntry.fields[key]);
|
|
1391
|
+
}
|
|
1385
1392
|
}
|
|
1386
1393
|
}
|
|
1387
1394
|
injectedUuids.push(syncPhaseUuid);
|
|
@@ -1429,7 +1436,12 @@ function injectSpmIntoPbxproj(
|
|
|
1429
1436
|
} else {
|
|
1430
1437
|
const existingPhase = findObjectByUuid(text, embedPhaseUuid);
|
|
1431
1438
|
if (existingPhase != null) {
|
|
1432
|
-
for (const key of [
|
|
1439
|
+
for (const key of [
|
|
1440
|
+
'shellScript',
|
|
1441
|
+
'inputPaths',
|
|
1442
|
+
'outputPaths',
|
|
1443
|
+
'shellPath',
|
|
1444
|
+
]) {
|
|
1433
1445
|
const current = findObjectByUuid(text, embedPhaseUuid);
|
|
1434
1446
|
if (current != null) {
|
|
1435
1447
|
text = setScalarField(text, current, key, embedEntry.fields[key]);
|
|
@@ -1606,6 +1618,7 @@ function injectSpmIntoPbxproj(
|
|
|
1606
1618
|
'shellScript',
|
|
1607
1619
|
'inputPaths',
|
|
1608
1620
|
'outputPaths',
|
|
1621
|
+
'shellPath',
|
|
1609
1622
|
]) {
|
|
1610
1623
|
const current = findObjectByUuid(text, uuid);
|
|
1611
1624
|
if (current != null) {
|
|
@@ -1876,11 +1889,40 @@ function addPreActionToScheme(
|
|
|
1876
1889
|
// value itself never contains one — the next `"` is always the closing
|
|
1877
1890
|
// delimiter.
|
|
1878
1891
|
const valueEnd = xml.indexOf('"', valueStart);
|
|
1879
|
-
|
|
1892
|
+
let xmlWithScript =
|
|
1880
1893
|
xml.slice(0, valueStart) +
|
|
1881
1894
|
escapeXmlAttribute(syncScript) +
|
|
1882
|
-
xml.slice(valueEnd)
|
|
1895
|
+
xml.slice(valueEnd);
|
|
1896
|
+
|
|
1897
|
+
// Xcode always runs a scheme pre-action's scriptText under the shell this
|
|
1898
|
+
// attribute names (default /bin/sh), independent of a
|
|
1899
|
+
// PBXShellScriptBuildPhase's own shellPath (see shellScriptPhase) — pin
|
|
1900
|
+
// it to bash too. `>` can't appear unescaped inside either attribute
|
|
1901
|
+
// value, so it reliably closes the ActionContent open tag. Search the
|
|
1902
|
+
// whole open tag (not just after scriptText) and allow any spacing
|
|
1903
|
+
// around `=`, since attribute order and formatting aren't guaranteed.
|
|
1904
|
+
const contentOpenIdx = xmlWithScript.lastIndexOf(
|
|
1905
|
+
'<ActionContent',
|
|
1906
|
+
titleIdx,
|
|
1883
1907
|
);
|
|
1908
|
+
const contentCloseIdx = xmlWithScript.indexOf('>', stIdx);
|
|
1909
|
+
const openTag = xmlWithScript.slice(contentOpenIdx, contentCloseIdx);
|
|
1910
|
+
const stiMatch = openTag.match(/shellToInvoke\s*=\s*"/);
|
|
1911
|
+
if (stiMatch != null) {
|
|
1912
|
+
const stiValueStart =
|
|
1913
|
+
contentOpenIdx + stiMatch.index + stiMatch[0].length;
|
|
1914
|
+
const stiValueEnd = xmlWithScript.indexOf('"', stiValueStart);
|
|
1915
|
+
xmlWithScript =
|
|
1916
|
+
xmlWithScript.slice(0, stiValueStart) +
|
|
1917
|
+
'/bin/bash' +
|
|
1918
|
+
xmlWithScript.slice(stiValueEnd);
|
|
1919
|
+
} else {
|
|
1920
|
+
xmlWithScript =
|
|
1921
|
+
xmlWithScript.slice(0, contentCloseIdx) +
|
|
1922
|
+
'\n shellToInvoke = "/bin/bash"' +
|
|
1923
|
+
xmlWithScript.slice(contentCloseIdx);
|
|
1924
|
+
}
|
|
1925
|
+
return xmlWithScript;
|
|
1884
1926
|
}
|
|
1885
1927
|
const refMatch = xml.match(
|
|
1886
1928
|
new RegExp(
|
|
@@ -1907,7 +1949,8 @@ function addPreActionToScheme(
|
|
|
1907
1949
|
` ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">\n` +
|
|
1908
1950
|
` <ActionContent\n` +
|
|
1909
1951
|
` title = "Sync SPM Autolinking"\n` +
|
|
1910
|
-
` scriptText = "${escapeXmlAttribute(syncScript)}"
|
|
1952
|
+
` scriptText = "${escapeXmlAttribute(syncScript)}"\n` +
|
|
1953
|
+
` shellToInvoke = "/bin/bash">\n` +
|
|
1911
1954
|
` <EnvironmentBuildable>\n` +
|
|
1912
1955
|
` ${cleanRef}\n` +
|
|
1913
1956
|
` </EnvironmentBuildable>\n` +
|
|
@@ -2181,7 +2224,7 @@ function readScriptPhasesManifest(
|
|
|
2181
2224
|
*/
|
|
2182
2225
|
function readMarker(
|
|
2183
2226
|
xcodeprojPath /*: string */,
|
|
2184
|
-
) /*: ?{generatedSources?: {[string]: Array<string>}, scriptPhases?: {[string]: string}, artifactsVersionOverride?: ?string, configCommand?: ?Array<string>, buildSettingChanges?: Array<BuildSettingChange>, createdArrayFields?: Array<CreatedArrayField>, scheme?: {file?: ?string, created?: ?boolean}, ...} */ {
|
|
2227
|
+
) /*: ?{targetUuid?: ?string, generatedSources?: {[string]: Array<string>}, scriptPhases?: {[string]: string}, artifactsVersionOverride?: ?string, configCommand?: ?Array<string>, buildSettingChanges?: Array<BuildSettingChange>, createdArrayFields?: Array<CreatedArrayField>, scheme?: {file?: ?string, created?: ?boolean}, ...} */ {
|
|
2185
2228
|
const markerPath = path.join(xcodeprojPath, SPM_INJECTED_MARKER);
|
|
2186
2229
|
try {
|
|
2187
2230
|
// $FlowFixMe[incompatible-return] JSON.parse returns any
|
|
@@ -2718,6 +2761,7 @@ module.exports = {
|
|
|
2718
2761
|
buildSchemePreActionScript,
|
|
2719
2762
|
buildEmbedFrameworksScript,
|
|
2720
2763
|
flavorForBuildConfiguration,
|
|
2764
|
+
targetBuildConfigUuids,
|
|
2721
2765
|
frameworkConditionalSettings,
|
|
2722
2766
|
ensureStubPackages,
|
|
2723
2767
|
buildSpmDependencyGraph,
|
|
@@ -2732,6 +2776,7 @@ module.exports = {
|
|
|
2732
2776
|
addPreActionToScheme,
|
|
2733
2777
|
removePreActionFromScheme,
|
|
2734
2778
|
findInjectedXcodeproj,
|
|
2779
|
+
readMarker,
|
|
2735
2780
|
readArtifactsVersionOverride,
|
|
2736
2781
|
readPinnedConfigCommand,
|
|
2737
2782
|
readScriptPhasesManifest,
|