Summary:
Two bugs in `addArrayStringValues`, which adds members to an array build setting (`HEADER_SEARCH_PATHS`, `OTHER_LDFLAGS`, `FRAMEWORK_SEARCH_PATHS`, `LD_RUNPATH_SEARCH_PATHS`). Both hit real projects; neither was visible from the existing fixture.
**1. A promoted scalar was never restored.** A setting that already exists as a scalar gets promoted to a `( … )` array, but that was recorded as a plain member-append — so `deinit` stripped the members and left the array shell plus its injected `"$(inherited)"` behind. Stock Xcode projects hit this: the app template sets `LD_RUNPATH_SEARCH_PATHS = "$(inherited) executable_path/Frameworks";` as a target-level scalar.
Fixed by pinning the pre-injection value in `.spm-injected.json` and restoring it in place. It is stored raw (a bare scalar's token runs to the `;`, carrying whitespace that must come back), recorded only if the merge actually changed the field, and not restored if the field is gone.
**2. A one-line array was corrupted.** The append anchored on `lastIndexOf('\n', tokenEnd - 1)`, which assumes multi-line. With no newline in the value that lands on the *previous* line, so members were spliced above the field, outside the array:
```
{
"/new", ← bare entry in the dict body: invalid pbxproj
HEADER_SEARCH_PATHS = ("/vendor", ); ← member never added
}
```
The result is a project Xcode cannot open, and `deinit` could not remove the stray line. Xcode writes multi-line arrays, but hand-edited projects and other generators (XcodeGen, Tuist) emit compact ones. Fixed by splicing inline ahead of the `)`; removal gained matching delimiter-anchored patterns, so the span removed is the span inserted. The dedupe parse was also quote-blind — a member holding a quoted comma parsed as two tokens — and is now quote-aware.
**Tradeoff:** reversing a promotion rewrites the whole field, so members hand-added to a promoted array afterwards are lost.
**Rebase note:** `main` has since grown an overlapping guard (`buildSettingValueTokens`) that skips the append when every value is already present, avoiding the *no-op* promotion. It is kept and complements this change: main still promotes irreversibly when there *is* a fresh value to add to a scalar, which is what the restore here covers. The two records stay mutually exclusive per key, pinned by a test.
## Changelog:
[Internal] [Fixed] - SwiftPM: `spm deinit` restores a promoted scalar build setting, and `spm add` no longer corrupts a one-line array
Pull Request resolved: https://github.com/react/react-native/pull/57744
Test Plan:
`yarn jest packages/react-native/scripts` → **963 tests, 32 suites** green; eslint, prettier and flow clean.
Written red first: byte-identical `add` → `deinit` round-trips for each pre-existing shape (absent, multi-line, bare and quoted scalars, and the one-line forms), plus `add` → `update` → `deinit`. The multi-line path is unchanged byte-for-byte, verified by a differential harness over 48 add/remove cases against the previous implementation.
Re-verified after the rebase on the committed `HelloWorld.xcodeproj`, driving the real `injectSpmIntoExistingXcodeproj` / `removeSpmInjection`. On `main` a one-line `HEADER_SEARCH_PATHS` gains a bare `"…/autolinking/headers",` entry above the field and never receives the member; with this change it lands inside the array, and a pre-existing scalar comes back exactly.
Reviewed By: fabriziocucci
Differential Revision: D114317839
Pulled By: cipolleschi
fbshipit-source-id: 08bc81f80855721bf2123143063462109a99ac25
Learn once, write anywhere:
Create native apps for Android, iOS, and more using React
Getting Started · Learn the Basics · Showcase · Contribute · Community · Support
React Native
React Native lets you build native apps using React. Written in JavaScript, rendered with native code.
- Native UI. React Native primitives render to native platform UI, meaning your app uses the same native platform APIs other apps do. Gestures, text scaling, and accessibility behave the way users expect on each OS.
- React, everywhere. Declarative UI, components, hooks, and Suspense, reused across Android, iOS, and other platforms.
- Developer Velocity. See local changes in seconds. Changes to JavaScript code are applied with Fast Refresh, without rebuilding the native app.
- Extend it yourself. Native Modules let you call platform code directly from JavaScript, synchronously and type-safe — or reach for thousands of existing libraries.
React Native is developed and supported by many companies and individual core contributors. Find out more on the React Foundation website.
Building your first React Native app
Follow the Getting Started guide for a new app, or Integration with Existing Apps to adopt React Native incrementally.
Using a Framework
We believe that the best way to experience React Native is through a Framework, a toolbox with all the necessary APIs to let you build production ready apps. Expo is a production-grade React Native Framework, with file-based routing, a standard library of native modules, and much more.
To create a new Expo project, run the following in your terminal:
npx create-expo-app@latest
Then follow the rest of Expo's getting started guide to start building.
Without a Framework
You can also use React Native without a Framework, however we've found that most developers benefit from one — navigation, native dependencies, and platform tooling are problems the ecosystem has already solved. If a Framework doesn't suit your app, follow Getting Started Without a Framework.
Documentation
The full documentation for React Native can be found on our website.
- Introduction
- Getting Started
- Learn the Basics
- Components and APIs
- UI & Interaction
- Native Modules
- Debugging
- Upgrading
- Architecture
The source for the React Native docs and website is hosted on a separate repository, react/react-native-website.
Contributing
The main purpose of this repository is to continue evolving React Native core. We want to make contributing to this project as easy and transparent as possible, and we are grateful to the community for contributing bug fixes and improvements. Read below to learn how you can take part in improving React Native.
Code of Conduct
Meta has adopted a Code of Conduct that we expect project participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated.
Contributing Guide
Read our Contributing Guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React Native.
Discussions
Larger discussions and proposals are discussed in react-native-community/discussions-and-proposals.
React Native releases are discussed in reactwg/react-native-releases.
License
React Native is MIT licensed, as found in the LICENSE file.