react-native 0.88.0-rc.0 → 0.88.0-rc.2
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/FBReactNativeSpec/FBReactNativeSpec.h +3 -4
- 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/core/iostests/RCTTurboModuleTests.mm +18 -65
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTInteropTurboModule.h +1 -2
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTInteropTurboModule.mm +1 -2
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h +2 -9
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +33 -71
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +6 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +3 -1
- package/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleTurboModule.mm +8 -19
- package/package.json +16 -13
- 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
- package/React/Base/RCTArrayBuffer.h +0 -64
- package/React/Base/RCTArrayBuffer.mm +0 -127
|
@@ -38,11 +38,14 @@ import type {
|
|
|
38
38
|
const {
|
|
39
39
|
SpmNameCollisionError,
|
|
40
40
|
defaultReadConfig,
|
|
41
|
+
defaultReadPodspec,
|
|
41
42
|
defaultResolveDep,
|
|
42
43
|
expandSpmDependencies,
|
|
44
|
+
resolveSwiftName,
|
|
43
45
|
} = require('./expand-spm-dependencies');
|
|
44
46
|
const {expandSpmSourceGlobs} = require('./generate-spm-autolinking');
|
|
45
|
-
const {
|
|
47
|
+
const {MIN_IOS_VERSION_SUPPORTED} = require('./ios-deployment-target');
|
|
48
|
+
const {findPodspecs, readPodspecCached} = require('./read-podspec');
|
|
46
49
|
const {
|
|
47
50
|
REACT_CODEGEN_PACKAGE_NAME,
|
|
48
51
|
REACT_CODEGEN_PRODUCTS,
|
|
@@ -51,12 +54,12 @@ const {
|
|
|
51
54
|
SCAFFOLDER_MARKER,
|
|
52
55
|
makeLogger,
|
|
53
56
|
remotePackageConfig,
|
|
54
|
-
toSwiftName,
|
|
55
57
|
} = require('./spm-utils');
|
|
58
|
+
const {readSwiftpmConfig, writeSwiftpmName} = require('./swiftpm-config');
|
|
56
59
|
const fs = require('node:fs');
|
|
57
60
|
const path = require('node:path');
|
|
58
61
|
|
|
59
|
-
const {log} = makeLogger('scaffold-package-swift');
|
|
62
|
+
const {log, warn} = makeLogger('scaffold-package-swift');
|
|
60
63
|
|
|
61
64
|
// SCAFFOLDER_MARKER lives in spm-utils.js (shared, no import cycle). It must NOT
|
|
62
65
|
// contain the autolinker's AUTOGEN_MARKER ('// AUTO-GENERATED by
|
|
@@ -105,7 +108,9 @@ const {log} = makeLogger('scaffold-package-swift');
|
|
|
105
108
|
// v19: scaffolded C++ targets carry DEBUG/NDEBUG config defines so their Fabric
|
|
106
109
|
// ABI matches the prebuilt React.framework (Release strips DebugStringConvertible
|
|
107
110
|
// under NDEBUG). Bumped so existing scaffolds regenerate with the defines.
|
|
108
|
-
|
|
111
|
+
// v20: the platform floor is the app's iOS deployment target in string form
|
|
112
|
+
// (the `.v15` enum cannot express a dependency minimum like 16.4).
|
|
113
|
+
const SCAFFOLDER_VERSION = 20;
|
|
109
114
|
const SCAFFOLDER_VERSION_LINE_RE = /^\/\/ AUTO-SCAFFOLDED-VERSION: (\d+)$/m;
|
|
110
115
|
|
|
111
116
|
const AUTOGEN_MARKER =
|
|
@@ -246,22 +251,16 @@ function translatePodspecToSpmTarget(
|
|
|
246
251
|
) /*: SpmScaffoldSpec */ {
|
|
247
252
|
const warnings = [...model.warnings];
|
|
248
253
|
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// (path-style includes like safe-area-context's
|
|
260
|
-
// `<react/renderer/components/safeareacontext/...>` resolve through
|
|
261
|
-
// `-I common/cpp/`). Module-style includes that NEED the target name to
|
|
262
|
-
// match (e.g. reanimated's `<reanimated/X.h>` via SwiftPM's auto-generated
|
|
263
|
-
// module map) are what `spm.name` is for.
|
|
264
|
-
const swiftName = dep.swiftName ?? toSwiftName(dep.name);
|
|
254
|
+
// Whatever the autolinker resolved (see resolveSwiftName). It registers the
|
|
255
|
+
// dep under that name in its aggregator and in any sibling spm.dependencies
|
|
256
|
+
// refs, so the scaffolded product/library name must match it exactly —
|
|
257
|
+
// otherwise SPM fails to resolve `.product(name: "X", package: "X")`.
|
|
258
|
+
const swiftName = dep.swiftName;
|
|
259
|
+
if (swiftName == null) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
`react-native spm scaffold: no resolved Swift name for '${dep.name}'. expandSpmDependencies must resolve every dep's name before a manifest is written.`,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
265
264
|
|
|
266
265
|
// Header search paths — substitute Xcode build-setting tokens against the
|
|
267
266
|
// dep root. Anything we can't substitute is dropped + warned (avoids
|
|
@@ -566,6 +565,7 @@ type EmitContext = {
|
|
|
566
565
|
// Relative path to the app's local xcframeworks package
|
|
567
566
|
// (<appRoot>/build/xcframeworks). Only referenced when remote == null.
|
|
568
567
|
localXcfwPackageDir?: ?string,
|
|
568
|
+
iosDeploymentTarget?: ?string,
|
|
569
569
|
};
|
|
570
570
|
*/
|
|
571
571
|
|
|
@@ -582,6 +582,8 @@ function emitScaffoldedPackageSwift(
|
|
|
582
582
|
) /*: string */ {
|
|
583
583
|
const slotComment =
|
|
584
584
|
ctx.cacheSlotLabel != null ? `\n// Cache slot: ${ctx.cacheSlotLabel}` : '';
|
|
585
|
+
const iosDeploymentTarget /*: string */ =
|
|
586
|
+
ctx.iosDeploymentTarget ?? MIN_IOS_VERSION_SUPPORTED;
|
|
585
587
|
|
|
586
588
|
// React headers need NO search paths — they come from the React /
|
|
587
589
|
// ReactNativeHeaders binaryTargets and the ReactAppHeaders product (see
|
|
@@ -658,8 +660,7 @@ function emitScaffoldedPackageSwift(
|
|
|
658
660
|
|
|
659
661
|
// Dependencies block. Always declares ReactNative if any React-core dep
|
|
660
662
|
// was in the podspec; sibling RN deps come from autolinking's existing
|
|
661
|
-
// .package(path: ...) graph
|
|
662
|
-
// since that's what the autolinker registers them under.
|
|
663
|
+
// .package(path: ...) graph, under the names the autolinker resolved.
|
|
663
664
|
const packageDeps /*: Array<string> */ = [];
|
|
664
665
|
const targetDeps /*: Array<string> */ = [];
|
|
665
666
|
if (spec.coreReactNative) {
|
|
@@ -704,8 +705,12 @@ function emitScaffoldedPackageSwift(
|
|
|
704
705
|
}
|
|
705
706
|
}
|
|
706
707
|
for (const siblingName of spec.siblingNames) {
|
|
707
|
-
const swiftSibling =
|
|
708
|
-
|
|
708
|
+
const swiftSibling = spec.siblingSwiftNames?.[siblingName];
|
|
709
|
+
if (swiftSibling == null) {
|
|
710
|
+
throw new Error(
|
|
711
|
+
`react-native spm scaffold: no resolved Swift name for the sibling '${siblingName}'. expandSpmDependencies must resolve every dep's name before a manifest is written.`,
|
|
712
|
+
);
|
|
713
|
+
}
|
|
709
714
|
// The autolinker references each self-managed (scaffolded) dep through a
|
|
710
715
|
// `libs/<SwiftName>` symlink, and SPM resolves a manifest's relative
|
|
711
716
|
// package paths against that symlink location — so a sibling lives at
|
|
@@ -766,7 +771,7 @@ import PackageDescription
|
|
|
766
771
|
|
|
767
772
|
let package = Package(
|
|
768
773
|
name: "${spec.swiftName}",
|
|
769
|
-
platforms: [.iOS(
|
|
774
|
+
platforms: [.iOS("${iosDeploymentTarget}")],
|
|
770
775
|
products: [
|
|
771
776
|
.library(name: "${spec.swiftName}", targets: ["${spec.swiftName}"]),
|
|
772
777
|
],
|
|
@@ -784,6 +789,61 @@ ${packageDepsBlock} targets: [
|
|
|
784
789
|
`;
|
|
785
790
|
}
|
|
786
791
|
|
|
792
|
+
const PODSPEC_KEY_ORIGINS = {
|
|
793
|
+
header_dir: "its podspec's 'header_dir'",
|
|
794
|
+
module_name: "its podspec's 'module_name'",
|
|
795
|
+
name: 'its pod name',
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
// Null when the caller resolved the name without recording where it came from,
|
|
799
|
+
// since the alternative is inventing an origin.
|
|
800
|
+
function swiftNameOrigin(dep /*: AutolinkedDep */) /*: ?string */ {
|
|
801
|
+
switch (dep.swiftNameSource) {
|
|
802
|
+
case 'config':
|
|
803
|
+
return "its declared 'swiftpmConfig.name'";
|
|
804
|
+
case 'podspec':
|
|
805
|
+
return PODSPEC_KEY_ORIGINS[dep.swiftNamePodspecKey ?? 'name'];
|
|
806
|
+
case 'npm':
|
|
807
|
+
return 'its npm package name';
|
|
808
|
+
default:
|
|
809
|
+
return null;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* Says which SwiftPM name the library got and where that name came from. The
|
|
815
|
+
* name is the prefix every `#import <Name/Header.h>` against the library has to
|
|
816
|
+
* spell, and a podspec-derived one is written into the library's package.json,
|
|
817
|
+
* so it is not a decision to make silently.
|
|
818
|
+
*/
|
|
819
|
+
function reportSwiftName(
|
|
820
|
+
dep /*: AutolinkedDep */,
|
|
821
|
+
swiftName /*: string */,
|
|
822
|
+
model /*: PodspecModel */,
|
|
823
|
+
) /*: void */ {
|
|
824
|
+
const origin = swiftNameOrigin(dep);
|
|
825
|
+
if (origin == null) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
log(`${dep.name}: SwiftPM name '${swiftName}' (from ${origin}).`);
|
|
829
|
+
// Two declared namespaces, one name: CocoaPods compiles the module as
|
|
830
|
+
// `module_name` while consumers import through `header_dir`, so a library
|
|
831
|
+
// that declares both loses one of them here.
|
|
832
|
+
const {headerDir, moduleName} = model;
|
|
833
|
+
if (
|
|
834
|
+
dep.swiftNamePodspecKey === 'header_dir' &&
|
|
835
|
+
headerDir != null &&
|
|
836
|
+
moduleName != null &&
|
|
837
|
+
headerDir !== moduleName
|
|
838
|
+
) {
|
|
839
|
+
warn(
|
|
840
|
+
`${dep.name}'s podspec declares both a 'header_dir' ('${headerDir}') and a 'module_name' ('${moduleName}'): ` +
|
|
841
|
+
`'${swiftName}' is the SwiftPM name, and '${moduleName}' is not used. ` +
|
|
842
|
+
`Set 'swiftpmConfig.name' in its package.json to override that choice.`,
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
787
847
|
// ---------------------------------------------------------------------------
|
|
788
848
|
// Per-dep orchestrator
|
|
789
849
|
// ---------------------------------------------------------------------------
|
|
@@ -806,9 +866,10 @@ type ScaffoldContext = {
|
|
|
806
866
|
// `s.dependency` names (e.g. "RNWorklets") wire to the right sibling.
|
|
807
867
|
podToNpm?: Map<string, string>,
|
|
808
868
|
// npm-name → resolved Swift name over all autolinked deps, so sibling
|
|
809
|
-
// references honor each sibling's
|
|
869
|
+
// references honor each sibling's declared name.
|
|
810
870
|
swiftNameByNpm?: Map<string, string>,
|
|
811
871
|
remote: ?{url: string, version: string, identity: string},
|
|
872
|
+
iosDeploymentTarget?: ?string,
|
|
812
873
|
};
|
|
813
874
|
*/
|
|
814
875
|
|
|
@@ -839,14 +900,14 @@ function scaffoldPackageSwiftForDep(
|
|
|
839
900
|
};
|
|
840
901
|
}
|
|
841
902
|
|
|
842
|
-
// Dep can opt out
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
903
|
+
// Dep can opt out in its own package.json.
|
|
904
|
+
if (
|
|
905
|
+
readSwiftpmConfig(dep.root, defaultReadConfig(dep.root))?.scaffold === false
|
|
906
|
+
) {
|
|
846
907
|
return {
|
|
847
908
|
depName,
|
|
848
909
|
status: 'skipped-opt-out',
|
|
849
|
-
reason:
|
|
910
|
+
reason: "the library sets 'swiftpmConfig.scaffold' to false.",
|
|
850
911
|
};
|
|
851
912
|
}
|
|
852
913
|
|
|
@@ -925,25 +986,10 @@ function scaffoldPackageSwiftForDep(
|
|
|
925
986
|
}
|
|
926
987
|
}
|
|
927
988
|
|
|
928
|
-
//
|
|
929
|
-
// otherwise glob for *.podspec in dep root.
|
|
989
|
+
// autolinking.json may have provided podspecPath; otherwise search dep.root.
|
|
930
990
|
// $FlowFixMe[prop-missing] dynamic shape from autolinking.json
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
try {
|
|
934
|
-
const entries = fs.readdirSync(dep.root);
|
|
935
|
-
// Skip a crashed run's leftover patched copy (read-podspec.js stages it
|
|
936
|
-
// as `.spm-scaffold-<pid>-<name>.podspec` next to the original).
|
|
937
|
-
const candidate = entries.find(
|
|
938
|
-
e => e.endsWith('.podspec') && !e.startsWith('.spm-scaffold-'),
|
|
939
|
-
);
|
|
940
|
-
if (candidate != null) {
|
|
941
|
-
podspecPath = path.join(dep.root, candidate);
|
|
942
|
-
}
|
|
943
|
-
} catch {
|
|
944
|
-
// dep.root may not exist; treat as no-podspec
|
|
945
|
-
}
|
|
946
|
-
}
|
|
991
|
+
const podspecPath /*: ?string */ =
|
|
992
|
+
dep.platforms.ios.podspecPath ?? findPodspecs(dep.root)[0];
|
|
947
993
|
if (podspecPath == null || !fs.existsSync(podspecPath)) {
|
|
948
994
|
return {
|
|
949
995
|
depName,
|
|
@@ -954,7 +1000,7 @@ function scaffoldPackageSwiftForDep(
|
|
|
954
1000
|
|
|
955
1001
|
let model;
|
|
956
1002
|
try {
|
|
957
|
-
model =
|
|
1003
|
+
model = readPodspecCached(podspecPath);
|
|
958
1004
|
} catch (e) {
|
|
959
1005
|
return {
|
|
960
1006
|
depName,
|
|
@@ -1023,6 +1069,7 @@ function scaffoldPackageSwiftForDep(
|
|
|
1023
1069
|
const content = emitScaffoldedPackageSwift(spec, {
|
|
1024
1070
|
cacheSlotLabel: ctx.cacheSlotLabel,
|
|
1025
1071
|
remote: ctx.remote,
|
|
1072
|
+
iosDeploymentTarget: ctx.iosDeploymentTarget,
|
|
1026
1073
|
codegenPackageDir: relFromManifest('build', 'generated', 'ios'),
|
|
1027
1074
|
localXcfwPackageDir: relFromManifest('build', 'xcframeworks'),
|
|
1028
1075
|
});
|
|
@@ -1064,15 +1111,171 @@ function scaffoldPackageSwiftForDep(
|
|
|
1064
1111
|
}
|
|
1065
1112
|
}
|
|
1066
1113
|
|
|
1114
|
+
reportSwiftName(dep, spec.swiftName, model);
|
|
1115
|
+
|
|
1116
|
+
// Migration: record a name we derived from the podspec, so the library can
|
|
1117
|
+
// drop the podspec. A declared name is already where it belongs, and a name
|
|
1118
|
+
// guessed from the npm name would freeze a guess into someone's config.
|
|
1119
|
+
const swiftpmName =
|
|
1120
|
+
dep.swiftNameSource === 'podspec'
|
|
1121
|
+
? writeSwiftpmName(dep.root, spec.swiftName, {dryRun: ctx.dryRun})
|
|
1122
|
+
: undefined;
|
|
1123
|
+
|
|
1067
1124
|
return {
|
|
1068
1125
|
depName,
|
|
1069
1126
|
status: 'written',
|
|
1070
1127
|
packageSwiftPath: pkgSwiftPath,
|
|
1071
1128
|
warnings: spec.warnings,
|
|
1072
1129
|
previouslyExisted,
|
|
1130
|
+
swiftpmName,
|
|
1073
1131
|
};
|
|
1074
1132
|
}
|
|
1075
1133
|
|
|
1134
|
+
/**
|
|
1135
|
+
* The dependency set the autolinker considers: the iOS entries of
|
|
1136
|
+
* autolinking.json plus their transitive SwiftPM dependencies. Null when the
|
|
1137
|
+
* file declares none; throws when it cannot be read or parsed. `onSkipped`
|
|
1138
|
+
* reports the entries dropped for having no iOS platform.
|
|
1139
|
+
*/
|
|
1140
|
+
function collectAutolinkedDeps(
|
|
1141
|
+
opts /*: {
|
|
1142
|
+
autolinkingJsonPath: string,
|
|
1143
|
+
remote: ?{url: string, version: string, identity: string},
|
|
1144
|
+
onSkipped?: (name: string) => void,
|
|
1145
|
+
} */,
|
|
1146
|
+
) /*: ?Array<AutolinkedDep> */ {
|
|
1147
|
+
const {autolinkingJsonPath, remote, onSkipped} = opts;
|
|
1148
|
+
/*:: type AutolinkingJson = {dependencies?: ?{[string]: {root?: string, platforms?: {ios?: ?{...}, ...}, ...}}, ...}; */
|
|
1149
|
+
// $FlowFixMe[incompatible-type] JSON.parse returns any
|
|
1150
|
+
const data /*: AutolinkingJson */ = JSON.parse(
|
|
1151
|
+
fs.readFileSync(autolinkingJsonPath, 'utf8'),
|
|
1152
|
+
);
|
|
1153
|
+
const deps = data.dependencies;
|
|
1154
|
+
if (deps == null) {
|
|
1155
|
+
return null;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
const directDeps /*: Array<AutolinkedDep> */ = [];
|
|
1159
|
+
for (const name of Object.keys(deps)) {
|
|
1160
|
+
const raw = deps[name];
|
|
1161
|
+
if (raw == null) continue;
|
|
1162
|
+
const root = raw.root;
|
|
1163
|
+
const ios = raw.platforms?.ios;
|
|
1164
|
+
if (typeof root !== 'string' || ios == null) {
|
|
1165
|
+
onSkipped?.(name);
|
|
1166
|
+
continue;
|
|
1167
|
+
}
|
|
1168
|
+
// $FlowFixMe[incompatible-type] `ios` shape is runtime-validated above
|
|
1169
|
+
const iosPlatform /*: AutolinkingIosPlatform */ = ios;
|
|
1170
|
+
directDeps.push({name, root, platforms: {ios: iosPlatform}});
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
try {
|
|
1174
|
+
return expandSpmDependencies(directDeps, {
|
|
1175
|
+
readConfig: defaultReadConfig,
|
|
1176
|
+
resolveDep: defaultResolveDep,
|
|
1177
|
+
readPodspec: defaultReadPodspec,
|
|
1178
|
+
extraReservedNames: remote != null ? [remote.identity] : undefined,
|
|
1179
|
+
});
|
|
1180
|
+
} catch (e) {
|
|
1181
|
+
if (e instanceof SpmNameCollisionError) {
|
|
1182
|
+
throw e;
|
|
1183
|
+
}
|
|
1184
|
+
// A transitive-resolution failure shouldn't abort the whole pass; fall back
|
|
1185
|
+
// to the direct deps so at least those are covered. They are named the way
|
|
1186
|
+
// the autolinker names them — a manifest written under any other name
|
|
1187
|
+
// outlives this error on disk and then fails to resolve.
|
|
1188
|
+
log(`Transitive dependency expansion failed: ${e.message}`);
|
|
1189
|
+
return directDeps.map(dep => {
|
|
1190
|
+
const resolved = resolveSwiftName(
|
|
1191
|
+
dep.name,
|
|
1192
|
+
readSwiftpmConfig(dep.root, defaultReadConfig(dep.root)),
|
|
1193
|
+
defaultReadPodspec(dep.root, dep.platforms.ios.podspecPath),
|
|
1194
|
+
);
|
|
1195
|
+
return {
|
|
1196
|
+
...dep,
|
|
1197
|
+
swiftName: resolved.name,
|
|
1198
|
+
swiftNameSource: resolved.source,
|
|
1199
|
+
swiftNamePodspecKey: resolved.podspecKey,
|
|
1200
|
+
};
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// The `.iOS(...)` element of the emitted platforms array — the `.v15` enum form
|
|
1206
|
+
// pre-v20 scaffolds carry included, and without the array's closing bracket so
|
|
1207
|
+
// a user-extended array (`[.iOS(…), .macOS(…)]`) is still matched.
|
|
1208
|
+
const PLATFORM_FLOOR_RE = /platforms: \[\.iOS\((\.v\d+|"[^"]*")\)/;
|
|
1209
|
+
|
|
1210
|
+
/**
|
|
1211
|
+
* Bring the platform floor of already-scaffolded manifests up to the app's
|
|
1212
|
+
* deployment target — `spm add`/`update` must not leave a dep pinned below the
|
|
1213
|
+
* app (SwiftPM would refuse to link it), and re-scaffolding is the user's call.
|
|
1214
|
+
* Only the platform line of a file carrying our own marker is rewritten; no
|
|
1215
|
+
* file is created. `from` is the previous token, verbatim (`15.1` or `.v15`).
|
|
1216
|
+
*/
|
|
1217
|
+
function refreshScaffoldedPlatformFloors(
|
|
1218
|
+
opts /*: {appRoot: string, autolinkingJsonPath?: string, iosDeploymentTarget: string} */,
|
|
1219
|
+
) /*: Array<{depName: string, path: string, from: string, to: string}> */ {
|
|
1220
|
+
const {appRoot, iosDeploymentTarget} = opts;
|
|
1221
|
+
const autolinkingJsonPath =
|
|
1222
|
+
opts.autolinkingJsonPath ??
|
|
1223
|
+
path.join(appRoot, 'build', 'generated', 'autolinking', 'autolinking.json');
|
|
1224
|
+
const refreshed = [];
|
|
1225
|
+
|
|
1226
|
+
// Best-effort: an unreadable autolinking.json, a name collision or a
|
|
1227
|
+
// malformed remote config is the autolinker's error to report a moment
|
|
1228
|
+
// later, not this pass's.
|
|
1229
|
+
let deps /*: ?Array<AutolinkedDep> */ = null;
|
|
1230
|
+
try {
|
|
1231
|
+
deps = collectAutolinkedDeps({
|
|
1232
|
+
autolinkingJsonPath,
|
|
1233
|
+
remote: remotePackageConfig(appRoot),
|
|
1234
|
+
});
|
|
1235
|
+
} catch {
|
|
1236
|
+
return refreshed;
|
|
1237
|
+
}
|
|
1238
|
+
if (deps == null) {
|
|
1239
|
+
return refreshed;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
for (const {name: depName, root} of deps) {
|
|
1243
|
+
const manifestPath = path.join(root, 'Package.swift');
|
|
1244
|
+
let content;
|
|
1245
|
+
try {
|
|
1246
|
+
content = fs.readFileSync(manifestPath, 'utf8');
|
|
1247
|
+
} catch {
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
if (
|
|
1251
|
+
!content.includes(SCAFFOLDER_MARKER) ||
|
|
1252
|
+
content.includes(AUTOGEN_MARKER)
|
|
1253
|
+
) {
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
const match = content.match(PLATFORM_FLOOR_RE);
|
|
1257
|
+
if (match == null) {
|
|
1258
|
+
continue;
|
|
1259
|
+
}
|
|
1260
|
+
const from = match[1].replace(/"/g, '');
|
|
1261
|
+
if (from === iosDeploymentTarget) {
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
fs.writeFileSync(
|
|
1265
|
+
manifestPath,
|
|
1266
|
+
content.replace(match[0], `platforms: [.iOS("${iosDeploymentTarget}")`),
|
|
1267
|
+
'utf8',
|
|
1268
|
+
);
|
|
1269
|
+
refreshed.push({
|
|
1270
|
+
depName,
|
|
1271
|
+
path: manifestPath,
|
|
1272
|
+
from,
|
|
1273
|
+
to: iosDeploymentTarget,
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
return refreshed;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1076
1279
|
// ---------------------------------------------------------------------------
|
|
1077
1280
|
// Multi-dep orchestrator
|
|
1078
1281
|
// ---------------------------------------------------------------------------
|
|
@@ -1086,6 +1289,7 @@ type ScaffoldAllOptions = {
|
|
|
1086
1289
|
dryRun?: boolean,
|
|
1087
1290
|
cacheSlotLabel?: ?string,
|
|
1088
1291
|
autolinkingJsonPath?: string,
|
|
1292
|
+
iosDeploymentTarget?: ?string,
|
|
1089
1293
|
// npm dep names to skip entirely — used when the user declined the
|
|
1090
1294
|
// confirmation prompt for first-time scaffolds. Skipped deps still
|
|
1091
1295
|
// appear in the returned results array with status='skipped-opt-out'.
|
|
@@ -1113,62 +1317,29 @@ function scaffoldAll(
|
|
|
1113
1317
|
return [];
|
|
1114
1318
|
}
|
|
1115
1319
|
|
|
1116
|
-
|
|
1117
|
-
//
|
|
1118
|
-
const data /*: AutolinkingJson */ = JSON.parse(
|
|
1119
|
-
fs.readFileSync(autolinkingJsonPath, 'utf8'),
|
|
1120
|
-
);
|
|
1121
|
-
const deps = data.dependencies;
|
|
1122
|
-
if (deps == null) {
|
|
1123
|
-
return [];
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
// Narrow the direct autolinking.json entries with an iOS platform, then
|
|
1127
|
-
// expand transitive `spm.dependencies` so the scaffolder covers EXACTLY the
|
|
1128
|
-
// set the autolinker considers. Without this, a transitive native dep that
|
|
1320
|
+
// The scaffolder covers EXACTLY the set the autolinker considers, transitive
|
|
1321
|
+
// `spm.dependencies` included. Without them, a transitive native dep that
|
|
1129
1322
|
// ships no Package.swift would be flagged by the autolinker but never
|
|
1130
1323
|
// scaffolded here — leaving `react-native spm scaffold` unable to clear the
|
|
1131
1324
|
// autolinker's missing-manifest error.
|
|
1132
1325
|
const results /*: Array<ScaffoldResult> */ = [];
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1326
|
+
// Outside collectAutolinkedDeps' own try: a malformed remote config
|
|
1327
|
+
// (RemoteVersionError) is a misconfiguration to surface, not an expansion
|
|
1328
|
+
// failure to degrade past.
|
|
1329
|
+
const remote = remotePackageConfig(appRoot);
|
|
1330
|
+
const allDeps = collectAutolinkedDeps({
|
|
1331
|
+
autolinkingJsonPath,
|
|
1332
|
+
remote,
|
|
1333
|
+
onSkipped: name => {
|
|
1140
1334
|
results.push({
|
|
1141
1335
|
depName: name,
|
|
1142
1336
|
status: 'skipped-no-ios',
|
|
1143
1337
|
reason: 'no iOS platform in autolinking.json',
|
|
1144
1338
|
});
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
directDeps.push({name, root, platforms: {ios: iosPlatform}});
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
// Outside the try: a malformed remote config (RemoteVersionError) is a
|
|
1153
|
-
// misconfiguration to surface, not an expansion failure to degrade past.
|
|
1154
|
-
const remote = remotePackageConfig(appRoot);
|
|
1155
|
-
|
|
1156
|
-
let allDeps /*: Array<AutolinkedDep> */ = [];
|
|
1157
|
-
try {
|
|
1158
|
-
allDeps = expandSpmDependencies(directDeps, {
|
|
1159
|
-
readConfig: defaultReadConfig,
|
|
1160
|
-
resolveDep: defaultResolveDep,
|
|
1161
|
-
extraReservedNames: remote != null ? [remote.identity] : undefined,
|
|
1162
|
-
log,
|
|
1163
|
-
});
|
|
1164
|
-
} catch (e) {
|
|
1165
|
-
if (e instanceof SpmNameCollisionError) {
|
|
1166
|
-
throw e;
|
|
1167
|
-
}
|
|
1168
|
-
// A transitive-resolution failure shouldn't abort the whole scaffold pass;
|
|
1169
|
-
// fall back to the direct deps so at least those get manifests.
|
|
1170
|
-
log(`Transitive spm.dependencies expansion failed: ${e.message}`);
|
|
1171
|
-
allDeps = directDeps;
|
|
1339
|
+
},
|
|
1340
|
+
});
|
|
1341
|
+
if (allDeps == null) {
|
|
1342
|
+
return results;
|
|
1172
1343
|
}
|
|
1173
1344
|
|
|
1174
1345
|
// Index every autolinked dep's podspec name → its npm name, so a dep that
|
|
@@ -1187,14 +1358,8 @@ function scaffoldAll(
|
|
|
1187
1358
|
// discover the podspec at the dep root so podspec-name sibling deps
|
|
1188
1359
|
// (e.g. `s.dependency "TestLibraryCommon"`) still wire to their npm
|
|
1189
1360
|
// package.
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
if (f.endsWith('.podspec') && !f.startsWith('.spm-scaffold-')) {
|
|
1193
|
-
podToNpm.set(path.basename(f, '.podspec'), dep.name);
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
} catch {
|
|
1197
|
-
// unreadable dep root — sibling wiring falls back to the warning path
|
|
1361
|
+
for (const found of findPodspecs(dep.root)) {
|
|
1362
|
+
podToNpm.set(path.basename(found, '.podspec'), dep.name);
|
|
1198
1363
|
}
|
|
1199
1364
|
}
|
|
1200
1365
|
}
|
|
@@ -1213,6 +1378,7 @@ function scaffoldAll(
|
|
|
1213
1378
|
force: opts.force === true,
|
|
1214
1379
|
dryRun: opts.dryRun === true,
|
|
1215
1380
|
cacheSlotLabel: opts.cacheSlotLabel ?? null,
|
|
1381
|
+
iosDeploymentTarget: opts.iosDeploymentTarget ?? null,
|
|
1216
1382
|
podToNpm,
|
|
1217
1383
|
swiftNameByNpm,
|
|
1218
1384
|
remote,
|
|
@@ -1238,6 +1404,7 @@ function scaffoldAll(
|
|
|
1238
1404
|
}
|
|
1239
1405
|
|
|
1240
1406
|
module.exports = {
|
|
1407
|
+
refreshScaffoldedPlatformFloors,
|
|
1241
1408
|
scaffoldAll,
|
|
1242
1409
|
scaffoldPackageSwiftForDep,
|
|
1243
1410
|
translatePodspecToSpmTarget,
|
|
@@ -267,19 +267,16 @@ function findProjectObject(text /*: string */) /*: ObjectRange | null */ {
|
|
|
267
267
|
return findObjectByUuid(text, m[1]);
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
/**
|
|
271
|
-
|
|
272
|
-
* name + body range for each. Used to pick the app target to inject into
|
|
273
|
-
* (and to refuse on ambiguity).
|
|
274
|
-
*/
|
|
275
|
-
function findApplicationTargets(
|
|
270
|
+
/** Visit every top-level object of a section, in file order. */
|
|
271
|
+
function forEachObjectInSection(
|
|
276
272
|
text /*: string */,
|
|
277
|
-
|
|
278
|
-
|
|
273
|
+
name /*: string */,
|
|
274
|
+
fn /*: (obj: {uuid: string, comment: ?string, bodyOpen: number, bodyClose: number}) => void */,
|
|
275
|
+
) /*: void */ {
|
|
276
|
+
const section = findSection(text, name);
|
|
279
277
|
if (section == null) {
|
|
280
|
-
return
|
|
278
|
+
return;
|
|
281
279
|
}
|
|
282
|
-
const out = [];
|
|
283
280
|
const re = /\n\t\t([0-9A-Fa-f]{24})(?: \/\* (.*?) \*\/)? = \{/g;
|
|
284
281
|
re.lastIndex = section.contentStart;
|
|
285
282
|
for (;;) {
|
|
@@ -287,25 +284,42 @@ function findApplicationTargets(
|
|
|
287
284
|
if (m == null || m.index >= section.end) {
|
|
288
285
|
break;
|
|
289
286
|
}
|
|
290
|
-
const uuid = m[1];
|
|
291
|
-
const comment = m[2];
|
|
292
287
|
const bodyOpen = text.indexOf('{', m.index);
|
|
293
288
|
const bodyClose = scanToClose(text, bodyOpen);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
289
|
+
fn({uuid: m[1], comment: m[2], bodyOpen, bodyClose});
|
|
290
|
+
re.lastIndex = bodyClose;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Every PBXNativeTarget whose productType is an application. Returns uuid +
|
|
296
|
+
* name + body range for each. Used to pick the app target to inject into
|
|
297
|
+
* (and to refuse on ambiguity).
|
|
298
|
+
*/
|
|
299
|
+
function findApplicationTargets(
|
|
300
|
+
text /*: string */,
|
|
301
|
+
) /*: Array<{uuid: string, name: string, bodyOpen: number, bodyClose: number}> */ {
|
|
302
|
+
const out = [];
|
|
303
|
+
forEachObjectInSection(
|
|
304
|
+
text,
|
|
305
|
+
'PBXNativeTarget',
|
|
306
|
+
({uuid, comment, bodyOpen, bodyClose}) => {
|
|
307
|
+
const obj = {uuid, bodyOpen, bodyClose};
|
|
308
|
+
const productType = findField(text, obj, 'productType');
|
|
309
|
+
if (
|
|
310
|
+
productType == null ||
|
|
311
|
+
!/com\.apple\.product-type\.application/.test(productType.value)
|
|
312
|
+
) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
300
315
|
const nameField = findField(text, obj, 'name');
|
|
301
316
|
const name =
|
|
302
317
|
nameField != null
|
|
303
318
|
? nameField.value.replace(/^"|"$/g, '')
|
|
304
319
|
: (comment ?? uuid);
|
|
305
320
|
out.push({uuid, name, bodyOpen, bodyClose});
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
}
|
|
321
|
+
},
|
|
322
|
+
);
|
|
309
323
|
return out;
|
|
310
324
|
}
|
|
311
325
|
|
|
@@ -766,6 +780,7 @@ module.exports = {
|
|
|
766
780
|
findSection,
|
|
767
781
|
findProjectObject,
|
|
768
782
|
findApplicationTargets,
|
|
783
|
+
forEachObjectInSection,
|
|
769
784
|
uuidsInArray,
|
|
770
785
|
detectFieldIndent,
|
|
771
786
|
insertObjectsIntoSection,
|