Skip to content

docs(swiftpm): rename __doc__ to __docs__, drop two superseded docs, correct the rest - #58006

Open
chrfalch wants to merge 8 commits into
mainfrom
claude/react-native-swiftpm-docs-d2bc96
Open

docs(swiftpm): rename __doc__ to __docs__, drop two superseded docs, correct the rest#58006
chrfalch wants to merge 8 commits into
mainfrom
claude/react-native-swiftpm-docs-d2bc96

Conversation

@chrfalch

@chrfalch chrfalch commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Rebased onto main after #57757, #57756, #57762 and #57744 landed. Because this
PR renames __doc__ and Prettier-formats every file, a hunk-level rebase was the
wrong tool — it stopped on the second of nine commits and the reformat commit then
conflicted with everything after it. So the history is replayed on top of the
new main instead, and reordered to put Prettier before the content edits, which
makes the substantive diff reviewable rather than tangled with reflow.

Verified nothing those four PRs added was lost: every heading on main survives
except the two this PR deliberately renames, and their facts — the
artifactsVersionOverride pin, the autolinking-config-command pin, the
pre-injection build-setting values, and the promoted-scalar caveat — are carried
into the new "Files the tool touches" table rather than sitting in a row this PR
deletes.

Summary:

Housekeeping and accuracy pass over packages/react-native/scripts/spm/__docs__.
Docs only — no code or test changes.

Rename. scripts/spm/__doc__ was the only __doc__ directory in the repo;
every other subsystem uses __docs__ (27+ directories, and the convention
documented in __docs__/GUIDELINES.md). The misspelling also meant these files
were published to npm: package.json includes scripts/spm in files and
excludes !**/__docs__/**, which the misspelled directory dodged.

Removed two superseded documents. rfc-spm-xcframework.md (707 lines) was a
stale ancestor of RFC0994, still describing spm init, xcodeproj generation, the
.xcodeproj.legacy rename migration, a spm clean command that does not exist,
stub Package.swift files and VFS overlays. spm-plugins-assessment.md evaluated
SwiftPM plugins as a replacement for the injected build phases — conclusion valid,
detail stale (it listed a "Prepare VFS Overlay" phase). Both have had their durable
content folded into RFC0994.

Corrected the remaining docs against the implementation. The substantive one:
auto-sync is two hooks, not one — a scheme pre-action in the app's shared
scheme plus the build phase. The docs described only the phase.

Two claims here are corrections of my own earlier drafts, made after testing them
on private/helloworld rather than reading the code:

  • Neither hook can bootstrap a clean checkout. With build/ deleted,
    xcodebuild -scheme … build fails in nine lines of log, Resolve Package Graph
    first, the pre-action never running. The one-time setup run really is required,
    and the ordering table now shows the measured sequence.
  • A sync failure is not unconditionally non-fatal. Exit 2 — a dependency with no
    Package.swift — maps to exit 1 and fails the build deliberately; only other
    non-zero codes warn. As written, the doc also contradicted the exit-2 behaviour
    documented elsewhere in the same file.

Smaller fixes: hermesvmhermes-engine (that name is in no code), plugin
watchPaths added to the staleness inputs, and the #auto-sync-build-phase
anchors left dangling by the heading rename.

Added a __docs__/README.md index, per GUIDELINES.md, plus a "Files the
tool touches"
table — there was no single answer to what the tool creates or
modifies. Writing it surfaced that add creates or appends to ios/.gitignore
(documented nowhere), and that deinit does not revert that block, anything
--deintegrate changed, or a promoted array setting — so the "exact inverse of
add" claim needed qualifying in three places.

Documented spm.dependencies, the SwiftPM analog of a podspec's
s.dependency, which was implemented but absent from every doc, and corrected the
scaffold prerequisite: it is add/update that stops, with a distinct exit code 2,
not the build.

Prettier-formatted the docs, in its own commit. These were the only unformatted
markdown files in the repository, so prettier --list-different "./**/*.md" goes
from three failures to clean.

Changelog:

[Internal] - SwiftPM docs: rename __doc__ to __docs__, remove two superseded
documents, and correct the rest against the implementation

Test Plan:

  • npx prettier --check "packages/react-native/scripts/spm/__docs__/*.md" passes;
    npx prettier --list-different "./**/*.md" is empty for the whole repo.
  • All 19 intra-doc anchor links verified against GitHub's slug rules; none dead.
    Every relative path out of the new README resolves, including the root-index hop.
  • npm pack --dry-run --ignore-scripts lists no scripts/spm/__docs__/ entries
    while every scripts/spm/*.js still ships.
  • The Prettier commit is content-neutral: comparing [A-Za-z0-9]+ token streams
    across it, all three files are identical word for word.
  • Behavioural claims traced to source: VALID_ACTIONS in setup-apple-spm.js;
    injectOrCreateScheme / addPreActionToScheme and the RC -eq 2 branch of
    buildSyncAutolinkingScript in generate-spm-xcodeproj.js; BUILTIN_FRAMEWORKS
    in flavored-frameworks.js; generateXCFrameworksPackageSwift in
    generate-spm-package.js; ensureGitignoreSpmEntries and its action === 'add'
    guard; expand-spm-dependencies.js; reportMissingManifests.
  • The fresh-clone and ordering claims were measured on private/helloworld with
    Xcode 26.6, both artifact flavors cached, and the app restored afterwards.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 19, 2026
@chrfalch
chrfalch requested a review from cipolleschi August 19, 2026 07:12
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Aug 19, 2026
chrfalch and others added 4 commits August 19, 2026 11:56
Summary:
`packages/react-native/scripts/spm/__doc__` was the only `__doc__` directory in
the repo; every other subsystem uses `__docs__` (27+ directories, and the
convention documented in `__docs__/GUIDELINES.md`). Pure directory rename, no
content changes.

This also stops shipping the SwiftPM design docs in the npm package:
`packages/react-native/package.json` includes `scripts/spm` in `files` and
excludes `!**/__docs__/**`, so the misspelled directory was being published.

Changelog: [Internal]

Test Plan:
- `git grep __doc__` returns no hits: nothing referenced the path by name.
- `npm pack --dry-run --ignore-scripts` in `packages/react-native` lists no
  `scripts/spm/__docs__/` entries while all `scripts/spm/*.js` remain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary:
Both documented designs that no longer exist, and both are superseded elsewhere.

`rfc-spm-xcframework.md` (707 lines) is a stale ancestor of RFC0994, maintained in
react-native-community/discussions-and-proposals. It still described `spm init` and
xcodeproj *generation* (the tool now injects in place via add/update/deinit), the
`<App>.xcodeproj.legacy` rename migration, a `spm clean` command that does not
exist, stub `Package.swift` files, VFS overlays, a top-level `spmModules` key, and
a sync step that self-heals a fresh clone (it cannot).

`spm-plugins-assessment.md` evaluated whether SwiftPM plugins could replace the
injected Xcode build phases. Its conclusion holds, but its detail did not: it
listed a "Prepare VFS Overlay" phase and used the pre-rename `autolinked/`
directory. The durable reasoning — plugin sandboxing, no access to
CONFIGURATION/BUILT_PRODUCTS_DIR, no post-build stage — has been folded into
RFC0994's Alternatives section, along with the content the deleted RFC uniquely
carried.

Changelog: [Internal]

Test Plan:
The only inbound link to either file was in the deleted RFC itself; a repo-wide
grep for both filenames now returns nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary:
The SwiftPM markdown was never Prettier-formatted, even though the repo's
`format-check` script globs `*.md`. These are the only unformatted markdown files
in the repository, so `prettier --list-different "./**/*.md"` goes from three
failures to clean — this fixes an existing red check rather than tidying one
directory.

Kept as its own commit, and placed before the content changes that follow, so the
substantive edits read as content rather than reflow.

Changelog: [Internal]

Test Plan:
- `npx prettier --check packages/react-native/scripts/spm/__docs__/*.md` passes.
- `npx prettier --list-different "./**/*.md"` is empty for the whole repo; on the
  parent commit it listed exactly these three files.
- Content-neutral: comparing `grep -oE '[A-Za-z0-9]+'` token streams before and
  after, all three files are identical word for word. Only wrapping, table
  padding, and Prettier's `*emphasis*` -> `_emphasis_` convention changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary:
Audited the docs against the code. Corrections:

- **Auto-sync is two hooks, not one.** `add`/`update` inject a scheme pre-action
  (in the app's *shared* scheme) *and* the `Sync SPM Autolinking` build phase. The
  docs described only the phase. Rewrote the section around both.
- **Neither hook can bootstrap a clean checkout.** The docs said the build phase
  "cannot bootstrap a fresh clone" and implied a pre-action would; measured on
  Xcode 26.6 with a freshly-injected app and `build/` deleted,
  `xcodebuild -scheme … build` fails in nine lines with `Resolve Package Graph`
  first and no trace of the pre-action. Resolution precedes *both* hooks, so the
  one-time setup run is genuinely required. The ordering table now shows the
  measured sequence, including where the pre-action really falls.
- **A sync failure is not unconditionally non-fatal.** The section ended by saying
  a failure "emits a `warning:` and exits 0". The generated script branches: exit 2
  — an autolinked dependency with no `Package.swift` — maps to `exit 1` and fails
  the build on purpose; only other non-zero codes warn. As written the doc also
  contradicted the exit-2 behaviour documented elsewhere in the same file.
- `hermesvm` -> `hermes-engine`. That name appears nowhere in the code;
  `BUILTIN_FRAMEWORKS` in `flavored-frameworks.js` uses `hermes-engine`.
- Added plugin `watchPaths` / `.spm-sync-watch-paths` to the staleness inputs.
- Fixed the `#auto-sync-build-phase` anchors left dangling by the heading rename,
  here and in `spm-autolinking-plugins.md`, plus the subject/verb agreement that
  followed from "phase" becoming "hooks".

Changelog: [Internal]

Test Plan:
Each claim traced to source: `injectOrCreateScheme` / `addPreActionToScheme` and
the `RC -eq 2` branch of `buildSyncAutolinkingScript` in
`generate-spm-xcodeproj.js`; `BUILTIN_FRAMEWORKS` in `flavored-frameworks.js`.
The fresh-clone and ordering claims were measured against `private/helloworld`
with both artifact flavors cached, and the app restored afterwards. Prettier clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chrfalch
chrfalch force-pushed the claude/react-native-swiftpm-docs-d2bc96 branch from baa7914 to 2e70b74 Compare August 19, 2026 10:02
chrfalch and others added 3 commits August 19, 2026 12:03
Summary:
There was no single answer to "what does `npx react-native spm` create or
modify" — the information was spread across a commit-oriented table, an ASCII
directory tree, and scattered prose. Replaced the "What to commit" section with
one table grouped by committed / gitignored / outside-the-repo, each row naming
the writing action and whether `deinit` undoes it.

Writing it surfaced two things nothing documented:

- `add` creates or appends to `ios/.gitignore` (a `# SPM – auto-generated at
  build time` block adding `Package.resolved`, `build/generated/`,
  `build/xcframeworks/`, `.build/`). A tracked file in the user's repo, mentioned
  nowhere.
- `deinit` does **not** revert that block, nor anything `--deintegrate` changed.
  The docs called `deinit` "the exact inverse of `add`"; it is exact with respect
  to the `.spm-injected.json` marker, which is what the marker tracks, but these
  edits fall outside it.

The marker's own description now states both of its roles — reversal record and
configuration store — since the `--version` and autolinking-config-command pins
live there too, and `deinit` drops them with it. The table also records the scheme
behaviour worth knowing: `deinit` deletes the scheme when `add` created it, and
otherwise strips only the pre-action.

The promoted-array-setting caveat is kept as-is; it is the third thing `deinit`
does not restore byte-for-byte, and the table now points at it.

Changelog: [Internal]

Test Plan:
Every row traced to source: `ensureGitignoreSpmEntries` and its `action === 'add'`
guard in `setup-apple-spm.js`; the scheme branch in `generate-spm-xcodeproj.js`
(`scheme.created === true` deletes, else `removePreActionFromScheme`); the absence
of any Podfile or `build/` handling in the deinit path; and the cache locations in
`download-spm-artifacts.js` (`~/Library/Caches/ReactNative/spm-artifacts/`, plus
the tarball cache shared with CocoaPods and `RCT_SKIP_CACHES`). Prettier clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary:
Two things implemented in the code and absent from the docs.

**`spm.dependencies`.** The SwiftPM analog of a podspec's `s.dependency` — how a
library declares it needs another native library — is implemented in
`expand-spm-dependencies.js` and was documented in no doc at all, so a library
author porting a podspec had no way to find the mechanism replacing
`s.dependency`. Added a section next to the other `react-native.config.js`
surfaces, noting it resolves recursively and is a library-author surface rather
than an app one.

**The scaffold prerequisite.** "Community packages without a `Package.swift`" said
the *build* fails. It is `spm add`/`update` that stops, during autolinking
generation, with exit code **2** — deliberately distinct so the Xcode sync hook can
treat it as a hard build error while staying lenient about transient sync failures.
Neither the exit code nor the reason `add`/`update` refuse to auto-scaffold (it
would hide a real gap in the dependency's SPM support) was written down. Also noted
that `scaffold` runs codegen and autolinking but does *not* inject, so a first-time
setup still needs the follow-up `npx react-native spm`, and added a troubleshooting
row keyed on the error text since that is what people will search for.

Changelog: [Internal]

Test Plan:
Traced to `expand-spm-dependencies.js` for the recursive expansion, and to
`reportMissingManifests` in `generate-spm-autolinking.js` plus its handling in
`setup-apple-spm.js`, where the `scaffold` action runs before the shared
codegen/autolinking steps and injection stays gated on `action === 'add'`.
Prettier clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary:
`__docs__/GUIDELINES.md` asks each subsystem to carry a `__docs__/README.md` entry
point linking to its parent and children, so the technical docs can be navigated by
following links. The SwiftPM docs had no entry point — you had to already know
which file to open. Removing two of the five documents made that more obvious.

The index orients the reader, points at RFC0994 for the motivation and migration
plan (the in-repo copy of that RFC was stale and has been removed), states the two
ideas that explain most of the architecture, and records the subsystem
relationships: `ios-prebuild` produces the artifacts consumed here, codegen's output
becomes a local package, and `@react-native-community/cli config` supplies the
autolinking metadata.

Also links SwiftPM from the root documentation index under Build system → iOS,
which had no children.

Changelog: [Internal]

Test Plan:
Every relative link resolves on disk, including the `../../../../../` hop to the
root index and the root index's link back in. All 19 intra-doc anchor links across
`__docs__/` verified against GitHub's slug rules: none dead. Prettier clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chrfalch
chrfalch force-pushed the claude/react-native-swiftpm-docs-d2bc96 branch from 2e70b74 to 6c979b2 Compare August 19, 2026 10:04
Summary:
`markdownlint-cli2`'s glob is `**/__docs__/*.md`, so these files were never linted
while they lived in `__doc__` — the same way the misspelling dodged the npm `files`
exclusion. Renaming the directory pulled them into the lint job for the first time
and surfaced four pre-existing violations:

- `spm-autolinking-plugins.md` — MD001. `flavoredFrameworks`, `watchPaths` and
  `scriptPhases` were `h4` directly under an `h2`, a two-level jump. They are
  subsections of "The contract", so they are now `h3`. `context.react` stays `h4`
  under the `h3` it belongs to, which is now a legal single-level step.
- `spm-scripts.md` — MD025. The "Reference / internals" divider was a second `h1`.
  It is now `h2`, and the four sections it introduces drop one level with it so the
  hierarchy still reads as "these are under Reference".
- Both files — MD040. The lifecycle diagram and the directory-layout tree are
  unlabelled fences; both are now `text`.

Demoting the headings does not move any anchors, since GitHub derives them from the
heading text rather than its level.

Changelog: [Internal]

Test Plan:
- `npx markdownlint-cli2` — the CI invocation, no path argument, so it lints all 38
  files under the repo's `__docs__` glob: 0 errors, down from 4.
- `npx prettier --check packages/react-native/scripts/spm/__docs__/*.md` passes.
- `npx eslint --max-warnings 0 packages/react-native/scripts/spm/` passes.
- All 20 intra-doc anchor links re-verified against GitHub's slug rules after the
  demotions: none dead. The config's own `link-fragments` rule agrees.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@meta-codesync

meta-codesync Bot commented Aug 19, 2026

Copy link
Copy Markdown

@cipolleschi has imported this pull request. If you are a Meta employee, you can view this in D116598871.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Expo Partner: Expo Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants