@depup/react-native 0.87.0-depup.0 → 0.87.1-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Libraries/Animated/AnimatedEvent.js +1 -1
- package/Libraries/Animated/AnimatedImplementation.js +6 -2
- package/Libraries/Animated/nodes/AnimatedNode.js +1 -1
- package/Libraries/Animated/nodes/AnimatedValue.js +2 -2
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/README.md +3 -3
- package/React/Base/RCTVersion.m +1 -1
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.kt +7 -3
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm +1 -1
- package/changes.json +2 -2
- package/package.json +12 -12
- package/scripts/cocoapods/rndependencies.rb +31 -25
- package/scripts/replace-rncore-version.js +18 -2
- package/scripts/setup-apple-spm.js +28 -12
- package/scripts/spm/autolinking-plugins.js +80 -0
- package/scripts/spm/download-spm-artifacts.js +64 -6
- package/scripts/spm/expand-spm-dependencies.js +249 -30
- package/scripts/spm/generate-spm-autolinking.js +157 -40
- package/scripts/spm/generate-spm-package.js +30 -18
- package/scripts/spm/generate-spm-xcodeproj.js +595 -71
- package/scripts/spm/scaffold-package-swift.js +65 -24
- package/scripts/spm/spm-pbxproj.js +158 -28
- package/scripts/spm/spm-types.js +29 -3
- package/scripts/spm/spm-utils.js +117 -2
- package/sdks/.hermesv1version +1 -1
- package/sdks/hermes-engine/version.properties +1 -1
- package/types_generated/Libraries/Animated/AnimatedImplementation.d.ts +2 -2
- package/types_generated/Libraries/Animated/nodes/AnimatedNode.d.ts +4 -1
- package/types_generated/Libraries/Animated/nodes/AnimatedValue.d.ts +3 -3
- package/scripts/spm/__doc__/rfc-spm-xcframework.md +0 -707
- package/scripts/spm/__doc__/spm-autolinking-plugins.md +0 -244
- package/scripts/spm/__doc__/spm-header-paths-contract.md +0 -97
- package/scripts/spm/__doc__/spm-plugins-assessment.md +0 -128
- package/scripts/spm/__doc__/spm-scripts.md +0 -486
|
@@ -393,15 +393,63 @@ async function resolveRNDepsArtifact(
|
|
|
393
393
|
return {url: snapshotUrl, version};
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
+
/**
|
|
397
|
+
* Resolves the `hermes-compiler` npm package's version from THIS project's own
|
|
398
|
+
* node_modules — the exact same lookup generate-spm-xcodeproj.js's
|
|
399
|
+
* resolveHermesCliPathSetting() uses to find the hermesc binary that will
|
|
400
|
+
* compile the JS bundle, and the same one react-native-xcode.sh falls back to
|
|
401
|
+
* for SwiftPM builds. Returns null when the package isn't resolvable (e.g.
|
|
402
|
+
* USE_HERMES=false apps that never installed it) so the caller can fall back
|
|
403
|
+
* to the npm dist-tag lookup.
|
|
404
|
+
*/
|
|
405
|
+
function resolveLocalHermesCompilerVersion(
|
|
406
|
+
rnRoot /*: string */,
|
|
407
|
+
) /*: string | null */ {
|
|
408
|
+
try {
|
|
409
|
+
const pkgPath = require.resolve('hermes-compiler/package.json', {
|
|
410
|
+
paths: [rnRoot],
|
|
411
|
+
});
|
|
412
|
+
// $FlowFixMe[incompatible-type] JSON.parse returns any
|
|
413
|
+
const pkg /*: {version: string} */ = JSON.parse(
|
|
414
|
+
fs.readFileSync(pkgPath, 'utf8'),
|
|
415
|
+
);
|
|
416
|
+
assertSafeVersion(pkg.version, 'local hermes-compiler/package.json');
|
|
417
|
+
return pkg.version;
|
|
418
|
+
} catch (error) {
|
|
419
|
+
// A MODULE_NOT_FOUND resolution failure is the expected case (e.g.
|
|
420
|
+
// USE_HERMES=false apps that never installed hermes-compiler) — fall back
|
|
421
|
+
// silently. Any other failure means hermes-compiler IS installed but its
|
|
422
|
+
// package.json is unreadable/malformed or carries an unsafe version; warn
|
|
423
|
+
// loudly rather than silently regressing to the live latest-v1 dist-tag,
|
|
424
|
+
// which would re-introduce the version-skew crash this resolves (#57917).
|
|
425
|
+
if (error.code !== 'MODULE_NOT_FOUND') {
|
|
426
|
+
log(
|
|
427
|
+
` WARNING: hermes-compiler is installed but its version could not be resolved (${error.message}); falling back to the latest-v1 dist-tag, which may not match the pinned hermesc and can crash at launch with "Wrong bytecode version".`,
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
396
434
|
/**
|
|
397
435
|
* Returns {url, version} for Hermes. Hermes uses its own version space
|
|
398
436
|
* decoupled from React Native's nightly cadence — RN's `hermes-compiler`
|
|
399
437
|
* npm package publishes a `latest-v1` dist-tag that always resolves to a
|
|
400
|
-
* binary that's been built and uploaded to Maven.
|
|
401
|
-
* CocoaPods prebuild path (see scripts/ios-prebuild/hermes.js):
|
|
438
|
+
* binary that's been built and uploaded to Maven.
|
|
402
439
|
*
|
|
403
|
-
* HERMES_VERSION unset →
|
|
404
|
-
*
|
|
440
|
+
* HERMES_VERSION unset → version pinned by the locally installed
|
|
441
|
+
* hermes-compiler package (node_modules).
|
|
442
|
+
* This is the SAME source
|
|
443
|
+
* resolveHermesCliPathSetting() reads for
|
|
444
|
+
* HERMES_CLI_PATH, so the downloaded VM and
|
|
445
|
+
* the hermesc that compiles the JS bundle
|
|
446
|
+
* always agree — a mismatched pair crashes at
|
|
447
|
+
* launch with "Wrong bytecode version" (#57917).
|
|
448
|
+
* Falls back to the 'latest-v1' npm dist-tag
|
|
449
|
+
* (RN's CocoaPods prebuild default; see
|
|
450
|
+
* scripts/ios-prebuild/hermes.js) only when
|
|
451
|
+
* hermes-compiler isn't locally resolvable.
|
|
452
|
+
* HERMES_VERSION=latest-v1 → 'latest-v1' dist-tag (explicit)
|
|
405
453
|
* HERMES_VERSION=nightly → hermes-compiler@nightly dist-tag
|
|
406
454
|
* HERMES_VERSION=<literal> → use that version verbatim
|
|
407
455
|
*
|
|
@@ -413,8 +461,17 @@ async function resolveHermesArtifact(
|
|
|
413
461
|
rnVersion /*: string */,
|
|
414
462
|
flavor /*: string */,
|
|
415
463
|
rawVersion /*: string | null */,
|
|
464
|
+
rnRoot /*: string */,
|
|
416
465
|
) /*: Promise<ResolvedArtifact> */ {
|
|
417
|
-
let version = process.env.HERMES_VERSION
|
|
466
|
+
let version = process.env.HERMES_VERSION;
|
|
467
|
+
|
|
468
|
+
if (version == null) {
|
|
469
|
+
const localVersion = resolveLocalHermesCompilerVersion(rnRoot);
|
|
470
|
+
if (localVersion != null) {
|
|
471
|
+
log(` Using locally pinned hermes-compiler: ${localVersion}`);
|
|
472
|
+
}
|
|
473
|
+
version = localVersion ?? 'latest-v1';
|
|
474
|
+
}
|
|
418
475
|
|
|
419
476
|
if (version === 'nightly') {
|
|
420
477
|
version = await resolveNightlyVersion('hermes-compiler');
|
|
@@ -1119,7 +1176,7 @@ async function main(argv /*:: ?: Array<string> */) /*: Promise<void> */ {
|
|
|
1119
1176
|
label: 'hermes',
|
|
1120
1177
|
name: 'hermes-engine',
|
|
1121
1178
|
resolve: () =>
|
|
1122
|
-
resolveHermesArtifact(resolvedRnVersion, flavor, rawVersion),
|
|
1179
|
+
resolveHermesArtifact(resolvedRnVersion, flavor, rawVersion, rnRoot),
|
|
1123
1180
|
sharedName: (v /*: string */) => `hermes-ios-${v}-${flavor}.tar.gz`,
|
|
1124
1181
|
},
|
|
1125
1182
|
];
|
|
@@ -1390,6 +1447,7 @@ module.exports = {
|
|
|
1390
1447
|
main,
|
|
1391
1448
|
resolveCacheSlotVersion,
|
|
1392
1449
|
resolveHermesArtifact,
|
|
1450
|
+
resolveLocalHermesCompilerVersion,
|
|
1393
1451
|
REQUIRED_ARTIFACTS,
|
|
1394
1452
|
validateArtifactsCache,
|
|
1395
1453
|
// Exposed for unit tests (pure / fetch-stubbable helpers).
|
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
const {toSwiftName} = require('./spm-utils');
|
|
13
|
+
const {RESERVED_SWIFT_NAMES, makeLogger, toSwiftName} = require('./spm-utils');
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
16
|
|
|
17
|
+
const {warn} = makeLogger('expand-spm-dependencies');
|
|
18
|
+
|
|
17
19
|
/**
|
|
18
20
|
* expand-spm-dependencies.js — Resolves transitive native deps declared via
|
|
19
21
|
* `spm.dependencies` in a library's react-native.config.js.
|
|
@@ -32,7 +34,7 @@ const path = require('path');
|
|
|
32
34
|
* list with autolinking-shaped entries so the downstream pipeline can convert
|
|
33
35
|
* each to an SPM target without further branching.
|
|
34
36
|
*
|
|
35
|
-
* I/O is injected (readConfig, resolveDep) so the logic stays pure and
|
|
37
|
+
* I/O is injected (readConfig, resolveDep, log) so the logic stays pure and
|
|
36
38
|
* testable.
|
|
37
39
|
*/
|
|
38
40
|
|
|
@@ -44,52 +46,232 @@ import type {AutolinkedDep} from './spm-types';
|
|
|
44
46
|
type RnConfig = {...};
|
|
45
47
|
type ReadConfig = (root: string) => ?RnConfig;
|
|
46
48
|
type ResolveDep = (name: string, fromRoot: string) => ?string;
|
|
49
|
+
type Log = (message: string) => void;
|
|
50
|
+
// Keyed by lower case, valued with the canonical spelling: two names differing
|
|
51
|
+
// only in case are not distinct enough for the build to keep the two apart.
|
|
52
|
+
type ReservedNames = ReadonlyMap<string, string>;
|
|
47
53
|
type Options = {
|
|
48
54
|
readConfig: ReadConfig,
|
|
49
55
|
resolveDep: ResolveDep,
|
|
56
|
+
// Names to reserve alongside RESERVED_SWIFT_NAMES, supplied by the caller
|
|
57
|
+
// (remote mode relabels the RN package) since this module reads no config.
|
|
58
|
+
extraReservedNames?: ?ReadonlyArray<string>,
|
|
59
|
+
log?: ?Log,
|
|
50
60
|
};
|
|
51
61
|
*/
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
/**
|
|
64
|
+
* A misconfiguration rather than a resolution failure: scaffoldAll degrades past
|
|
65
|
+
* a transitive dep it cannot find, but must still surface this.
|
|
66
|
+
*/
|
|
67
|
+
class SpmNameCollisionError extends Error {
|
|
68
|
+
constructor(message /*: string */) {
|
|
69
|
+
super(message);
|
|
70
|
+
this.name = 'SpmNameCollisionError';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// The charset `spm.name` must satisfy — permissive on purpose, since it has to
|
|
75
|
+
// admit header-dir style (lowercase with hyphens) as well as Swift identifiers.
|
|
76
|
+
// Shared with the app's own `spm.modules` names.
|
|
77
|
+
function isValidSwiftName(name /*: unknown */) /*: boolean */ {
|
|
78
|
+
return typeof name === 'string' && /^[A-Za-z_][A-Za-z0-9_-]*$/.test(name);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function reservedSwiftNames(
|
|
82
|
+
extraReservedNames /*: ?ReadonlyArray<string> */,
|
|
83
|
+
) /*: ReservedNames */ {
|
|
84
|
+
return new Map(
|
|
85
|
+
[...RESERVED_SWIFT_NAMES, ...(extraReservedNames ?? [])].map(name => [
|
|
86
|
+
name.toLowerCase(),
|
|
87
|
+
name,
|
|
88
|
+
]),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// The scope-borrowed form of a name: `@powersync/react-native`'s `ReactNative`
|
|
93
|
+
// becomes `PowersyncReactNative`.
|
|
94
|
+
function scopeBorrowedName(
|
|
95
|
+
npmName /*: string */,
|
|
96
|
+
swiftName /*: string */,
|
|
97
|
+
) /*: ?string */ {
|
|
98
|
+
const scope = /^@([^/]+)\//.exec(npmName)?.[1];
|
|
99
|
+
return scope == null ? null : `${toSwiftName(scope)}${swiftName}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// The Swift target name for one dep, judged in isolation. `spm.name` is for
|
|
103
|
+
// libraries whose import prefix differs from the derived name:
|
|
104
|
+
// `react-native-worklets` ships headers as `<worklets/...>` (podspec
|
|
105
|
+
// `s.header_dir`), so its target is `worklets`, not `ReactNativeWorklets`. A
|
|
106
|
+
// derived name that lands on a reserved one borrows the npm scope instead.
|
|
59
107
|
function resolveSwiftName(
|
|
60
108
|
npmName /*: string */,
|
|
61
109
|
config /*: ?RnConfig */,
|
|
110
|
+
reserved /*: ReservedNames */,
|
|
111
|
+
log /*:: ?: ?Log */,
|
|
62
112
|
) /*: string */ {
|
|
63
113
|
// $FlowFixMe[prop-missing] config has dynamic shape
|
|
64
114
|
const override = config?.spm?.name;
|
|
65
|
-
if (override
|
|
66
|
-
|
|
115
|
+
if (override != null) {
|
|
116
|
+
if (typeof override !== 'string' || override.length === 0) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`react-native autolinking: '${npmName}' has an invalid 'spm.name' override: expected a non-empty string, got ${JSON.stringify(override)}.`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
if (!isValidSwiftName(override)) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`react-native autolinking: '${npmName}' has an invalid 'spm.name' override '${override}': must start with a letter or underscore and contain only letters, digits, underscores, or hyphens.`,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return override;
|
|
67
127
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
128
|
+
|
|
129
|
+
const derived = toSwiftName(npmName);
|
|
130
|
+
if (!reserved.has(derived.toLowerCase())) {
|
|
131
|
+
return derived;
|
|
72
132
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
133
|
+
const disambiguated = scopeBorrowedName(npmName, derived);
|
|
134
|
+
if (disambiguated == null || reserved.has(disambiguated.toLowerCase())) {
|
|
135
|
+
return derived;
|
|
136
|
+
}
|
|
137
|
+
log?.(
|
|
138
|
+
`'${npmName}' would take React Native's reserved name '${derived}', so its npm scope is prepended: '${disambiguated}'. ` +
|
|
139
|
+
`Set 'spm.name' in ${npmName}'s react-native.config.js to choose the name yourself.`,
|
|
140
|
+
);
|
|
141
|
+
return disambiguated;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function assertNameNotReserved(
|
|
145
|
+
swiftName /*: string */,
|
|
146
|
+
reserved /*: ReservedNames */,
|
|
147
|
+
labels /*: {label: string, remedy: string} */,
|
|
148
|
+
) /*: void */ {
|
|
149
|
+
const reservedName = reserved.get(swiftName.toLowerCase());
|
|
150
|
+
if (reservedName == null) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Vaguer about the case clash than the dep-vs-dep message on purpose: this
|
|
154
|
+
// set spans package identities and product names, which collide differently.
|
|
155
|
+
throw new SpmNameCollisionError(
|
|
156
|
+
`react-native autolinking: SPM Swift name collision: ${labels.label} resolves to '${swiftName}', ` +
|
|
157
|
+
(reservedName === swiftName
|
|
158
|
+
? `which React Native reserves for its own SPM package and products.`
|
|
159
|
+
: `which differs from React Native's reserved '${reservedName}' only in case — not distinct enough for the build to keep the two apart.`) +
|
|
160
|
+
` ${labels.remedy}`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Throws when `swiftName` is one React Native's own manifests use. `remedy` is
|
|
166
|
+
* the fix: a library sets `spm.name`, an app renames its `spm.modules` entry.
|
|
167
|
+
*/
|
|
168
|
+
function assertSwiftNameNotReserved(
|
|
169
|
+
swiftName /*: string */,
|
|
170
|
+
options /*: {
|
|
171
|
+
label: string,
|
|
172
|
+
remedy: string,
|
|
173
|
+
extraReservedNames?: ?ReadonlyArray<string>,
|
|
174
|
+
} */,
|
|
175
|
+
) /*: void */ {
|
|
176
|
+
const {label, remedy, extraReservedNames} = options;
|
|
177
|
+
assertNameNotReserved(swiftName, reservedSwiftNames(extraReservedNames), {
|
|
178
|
+
label,
|
|
179
|
+
remedy,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Reserved-name backstop over the resolved set. Unconditional: a plugin-shipping
|
|
184
|
+
// library is checked like any other, so `spm scaffold` — which knows nothing
|
|
185
|
+
// about plugins — cannot disagree with the autolinker about the same dep.
|
|
186
|
+
function assertNoReservedSwiftNames(
|
|
187
|
+
deps /*: ReadonlyArray<AutolinkedDep> */,
|
|
188
|
+
reserved /*: ReservedNames */,
|
|
189
|
+
) /*: void */ {
|
|
190
|
+
for (const dep of deps) {
|
|
191
|
+
const swiftName = dep.swiftName;
|
|
192
|
+
if (swiftName == null) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
assertNameNotReserved(swiftName, reserved, {
|
|
196
|
+
label: `'${dep.name}'`,
|
|
197
|
+
remedy: `Set a different 'spm.name' in ${dep.name}'s react-native.config.js.`,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Pulls apart deps that resolved to the same name by borrowing their npm scopes.
|
|
203
|
+
// Every scoped member of a colliding group moves: there is no non-arbitrary
|
|
204
|
+
// winner to keep. Exactly one pass — retrying would trade a diagnosable error
|
|
205
|
+
// for a name nobody can predict.
|
|
206
|
+
function disambiguateSharedSwiftNames(
|
|
207
|
+
deps /*: ReadonlyArray<AutolinkedDep> */,
|
|
208
|
+
autoNamed /*: ReadonlySet<string> */,
|
|
209
|
+
log /*: ?Log */,
|
|
210
|
+
) /*: void */ {
|
|
211
|
+
const groups /*: Map<string, Array<{dep: AutolinkedDep, swiftName: string}>> */ =
|
|
212
|
+
new Map();
|
|
213
|
+
for (const dep of deps) {
|
|
214
|
+
const swiftName = dep.swiftName;
|
|
215
|
+
if (swiftName == null) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const key = swiftName.toLowerCase();
|
|
219
|
+
const group = groups.get(key);
|
|
220
|
+
if (group == null) {
|
|
221
|
+
groups.set(key, [{dep, swiftName}]);
|
|
222
|
+
} else {
|
|
223
|
+
group.push({dep, swiftName});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
for (const group of groups.values()) {
|
|
228
|
+
if (group.length < 2) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
for (const {dep, swiftName} of group) {
|
|
232
|
+
// A name we derived can borrow a second time (`AAReactNative`); the
|
|
233
|
+
// member whose name we did not derive is the incumbent and keeps it.
|
|
234
|
+
if (!autoNamed.has(dep.name)) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const borrowed = scopeBorrowedName(dep.name, swiftName);
|
|
238
|
+
if (borrowed == null) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const others = group
|
|
242
|
+
.filter(other => other.dep !== dep)
|
|
243
|
+
.map(other => `'${other.dep.name}'`)
|
|
244
|
+
.join(', ');
|
|
245
|
+
log?.(
|
|
246
|
+
`'${dep.name}' would share the name '${swiftName}' with ${others}, so its npm scope is prepended: '${borrowed}'. ` +
|
|
247
|
+
`Set 'spm.name' in ${dep.name}'s react-native.config.js to choose the name yourself.`,
|
|
248
|
+
);
|
|
249
|
+
dep.swiftName = borrowed;
|
|
250
|
+
}
|
|
80
251
|
}
|
|
81
|
-
return override;
|
|
82
252
|
}
|
|
83
253
|
|
|
84
254
|
function expandSpmDependencies(
|
|
85
255
|
directDeps /*: Array<AutolinkedDep> */,
|
|
86
256
|
options /*: Options */,
|
|
87
257
|
) /*: Array<AutolinkedDep> */ {
|
|
88
|
-
const {readConfig, resolveDep} = options;
|
|
258
|
+
const {readConfig, resolveDep, extraReservedNames, log} = options;
|
|
259
|
+
const reserved = reservedSwiftNames(extraReservedNames);
|
|
89
260
|
const byName /*: Map<string, AutolinkedDep> */ = new Map();
|
|
90
261
|
for (const dep of directDeps) {
|
|
91
262
|
byName.set(dep.name, {...dep, spmDependencies: []});
|
|
92
263
|
}
|
|
264
|
+
const autoNamed /*: Set<string> */ = new Set();
|
|
265
|
+
const resolveName = (
|
|
266
|
+
npmName /*: string */,
|
|
267
|
+
config /*: ?RnConfig */,
|
|
268
|
+
) /*: string */ => {
|
|
269
|
+
// $FlowFixMe[prop-missing] config has dynamic shape
|
|
270
|
+
if (config?.spm?.name == null) {
|
|
271
|
+
autoNamed.add(npmName);
|
|
272
|
+
}
|
|
273
|
+
return resolveSwiftName(npmName, config, reserved, log);
|
|
274
|
+
};
|
|
93
275
|
|
|
94
276
|
const queue /*: Array<string> */ = directDeps.map(d => d.name);
|
|
95
277
|
while (queue.length > 0) {
|
|
@@ -105,7 +287,7 @@ function expandSpmDependencies(
|
|
|
105
287
|
// Resolve swiftName lazily from the same config read we already need for
|
|
106
288
|
// spm.dependencies — saves a duplicate readConfig call per direct dep.
|
|
107
289
|
if (current.swiftName == null) {
|
|
108
|
-
current.swiftName =
|
|
290
|
+
current.swiftName = resolveName(currentName, config);
|
|
109
291
|
}
|
|
110
292
|
// $FlowFixMe[prop-missing] config has dynamic shape
|
|
111
293
|
const transitives /*: Array<string> */ = config?.spm?.dependencies ?? [];
|
|
@@ -134,7 +316,7 @@ function expandSpmDependencies(
|
|
|
134
316
|
name: transitiveName,
|
|
135
317
|
root: transitiveRoot,
|
|
136
318
|
platforms: {ios: iosPlatform},
|
|
137
|
-
swiftName:
|
|
319
|
+
swiftName: resolveName(transitiveName, transitiveConfig),
|
|
138
320
|
spmDependencies: [],
|
|
139
321
|
});
|
|
140
322
|
queue.push(transitiveName);
|
|
@@ -144,6 +326,14 @@ function expandSpmDependencies(
|
|
|
144
326
|
current.spmDependencies = currentSpmDeps;
|
|
145
327
|
}
|
|
146
328
|
|
|
329
|
+
const allDeps /*: Array<AutolinkedDep> */ = Array.from(byName.values());
|
|
330
|
+
|
|
331
|
+
disambiguateSharedSwiftNames(allDeps, autoNamed, log);
|
|
332
|
+
|
|
333
|
+
// Both checks below validate the FINAL set, after that pass: a borrowed scope
|
|
334
|
+
// can land on a reserved name, or on one another dep already holds.
|
|
335
|
+
assertNoReservedSwiftNames(allDeps, reserved);
|
|
336
|
+
|
|
147
337
|
// Collision check: two deps mapping to the same Swift name (whether via
|
|
148
338
|
// override or auto-derivation) would clobber each other in the synth
|
|
149
339
|
// package layout and the centralized headers tree. Surface it now with a
|
|
@@ -154,7 +344,7 @@ function expandSpmDependencies(
|
|
|
154
344
|
// passes but the two still collide as directories on the default
|
|
155
345
|
// case-insensitive macOS filesystem (synth package layout + headers tree).
|
|
156
346
|
const seen /*: Map<string, {name: string, swiftName: string}> */ = new Map();
|
|
157
|
-
for (const dep of
|
|
347
|
+
for (const dep of allDeps) {
|
|
158
348
|
const swiftName = dep.swiftName;
|
|
159
349
|
if (swiftName == null) {
|
|
160
350
|
continue;
|
|
@@ -163,7 +353,7 @@ function expandSpmDependencies(
|
|
|
163
353
|
const existing = seen.get(key);
|
|
164
354
|
if (existing != null) {
|
|
165
355
|
const same = existing.swiftName === swiftName;
|
|
166
|
-
throw new
|
|
356
|
+
throw new SpmNameCollisionError(
|
|
167
357
|
`react-native autolinking: SPM Swift name collision: '${existing.name}' ('${existing.swiftName}') and '${dep.name}' ('${swiftName}') ` +
|
|
168
358
|
(same
|
|
169
359
|
? `both resolve to '${swiftName}'.`
|
|
@@ -174,7 +364,7 @@ function expandSpmDependencies(
|
|
|
174
364
|
seen.set(key, {name: dep.name, swiftName});
|
|
175
365
|
}
|
|
176
366
|
|
|
177
|
-
return
|
|
367
|
+
return allDeps;
|
|
178
368
|
}
|
|
179
369
|
|
|
180
370
|
// ---------------------------------------------------------------------------
|
|
@@ -188,8 +378,34 @@ function defaultReadConfig(root /*: string */) /*: ?RnConfig */ {
|
|
|
188
378
|
}
|
|
189
379
|
try {
|
|
190
380
|
// $FlowFixMe[unsupported-syntax]
|
|
191
|
-
|
|
192
|
-
|
|
381
|
+
const mod = require(configPath);
|
|
382
|
+
// Read both export styles, because the community CLI's two loaders
|
|
383
|
+
// disagree with each other: its sync path (`loadConfig`) requires the
|
|
384
|
+
// module and sees named exports at top level, its async path
|
|
385
|
+
// (`loadConfigAsync`) takes the default export only. Merging covers both,
|
|
386
|
+
// with named exports winning — the shape the sync path already resolves.
|
|
387
|
+
// Every sibling key of the default export is preserved
|
|
388
|
+
// (`dependency.platforms.ios` is read from this result too).
|
|
389
|
+
// A function-style config (`module.exports = () => ({...})`) and other
|
|
390
|
+
// non-objects pass through untouched — there is no default export to
|
|
391
|
+
// unwrap, and nulling them would hide a config that used to be read.
|
|
392
|
+
if (mod == null || typeof mod !== 'object') {
|
|
393
|
+
return mod;
|
|
394
|
+
}
|
|
395
|
+
const dflt = mod.default;
|
|
396
|
+
if (dflt == null || typeof dflt !== 'object') {
|
|
397
|
+
return mod;
|
|
398
|
+
}
|
|
399
|
+
const {default: _unused, ...named} = mod;
|
|
400
|
+
return {...dflt, ...named};
|
|
401
|
+
} catch (e) {
|
|
402
|
+
// A config can fail to load for reasons unrelated to SPM (it may import a
|
|
403
|
+
// devDependency absent in a consumer install), so this stays a warning —
|
|
404
|
+
// but a silent null turns a dropped `spm` block into a link error much
|
|
405
|
+
// later.
|
|
406
|
+
warn(
|
|
407
|
+
`Failed to load ${configPath}: ${e.message}. Any 'spm' settings in it are ignored.`,
|
|
408
|
+
);
|
|
193
409
|
return null;
|
|
194
410
|
}
|
|
195
411
|
}
|
|
@@ -209,7 +425,10 @@ function defaultResolveDep(
|
|
|
209
425
|
}
|
|
210
426
|
|
|
211
427
|
module.exports = {
|
|
428
|
+
SpmNameCollisionError,
|
|
429
|
+
assertSwiftNameNotReserved,
|
|
212
430
|
expandSpmDependencies,
|
|
431
|
+
isValidSwiftName,
|
|
213
432
|
resolveSwiftName,
|
|
214
433
|
defaultReadConfig,
|
|
215
434
|
defaultResolveDep,
|