diff --git a/.ai/commands/merge-minor.md b/.ai/commands/merge-minor.md new file mode 100644 index 000000000000..d8fafe2795ae --- /dev/null +++ b/.ai/commands/merge-minor.md @@ -0,0 +1,704 @@ +# Merge React Native Minor Release(s) + +Prepare, recreate, validate, and document React Native minor-version merge and +stable-release branches without flattening history or mixing mainline and stable +DAGs. + +## Arguments + +Accept: + +```text + [--mode fork-merge|stable-sync|stack|stack-recreate|focused-extraction] [--base ] [--onto ] [--dry-run] +.. [--mode stack|stack-recreate] [--base ] [--onto ] [--dry-run] +``` + +Examples: + +```text +0.84 +0.84 --mode fork-merge +0.84 --mode stable-sync --base 0.84-merge --onto 0.84-stable +0.84..0.87 --mode stack +0.86 --mode stack-recreate --base --onto +0.87 --mode focused-extraction +``` + +- Normalize each minor to `0.`. +- Default one minor to `fork-merge`; a range defaults to `stack`. +- Process ranges in ascending order. +- `--base` overrides the Microsoft predecessor ref. +- `--onto` overrides the Microsoft destination/base ref. +- `--dry-run` performs discovery, graph simulation, assertions, conflict + counting, and reporting without creating refs, merging, rebasing, committing, + pushing, or changing publication state. + +## Conventions + +### Non-negotiable DAG model + +Maintain two separate histories: + +```text +Microsoft mainline: +main -> 0.84-merge -> 0.85-merge -> 0.86-merge -> 0.87-merge + \ exact upstream fork points only + +Stable release lines: +0.84-merge (landed result) -> 0.84-stable -> pinned facebook/0.84-stable tip +0.85-merge (landed result) -> 0.85-stable -> pinned facebook/0.85-stable tip +``` + +- A mainline minor chains from the prior landed `*-merge` result, or `main` for + the first requested minor. +- A stable line forks from the matching landed minor result. +- Never merge a `facebook/-stable` tip into `main`, another mainline + merge branch, or a different minor. +- The `fork-merge` mechanical commit is an ordered two-parent Git merge: + parent 1 is the exact Microsoft predecessor and parent 2 is the exact + Facebook main/stable fork point. +- The `stable-sync` mechanical commit is also ordered: parent 1 is the exact + matching Microsoft stable base and parent 2 is the pinned Facebook stable + tip. +- Refuse to mutate `main`, any `*-stable` branch, or the main checkout. Every + writer uses a dedicated feature worktree/session. + +`*-merge`, release, and stacked branches are recreatable preparation baselines, +not immutable release truth. Human review edits can require rebasing or +recreation. Preserve backup refs, evidence, and old-to-new commit maps, then +rerun every semantic gate and obtain a fresh independent judgment. The upstream +fork-point or stable-tip SHA selected for one run remains immutable; a moved +upstream ref starts a new run. + +### Git is authoritative + +Resolve all refs to full object IDs before canonical commands: + +```bash +BASE_SHA=$(git rev-parse --verify "^{commit}") +TARGET_SHA=$(git rev-parse --verify "^{commit}") +HEAD_SHA=$(git rev-parse --verify "HEAD^{commit}") +printf '%s\n' "$BASE_SHA" "$TARGET_SHA" "$HEAD_SHA" +``` + +Use full SHAs in state, assertions, merge/rebase commands, evidence, and PR +notes. Abbreviations are display-only. Record relevant repository-local config, +Git version, argument order and label text, and `LC_ALL`; conflict renderings and +derived hashes can change with `merge.conflictStyle`, `core.abbrev`, argument +labels/order, Git version, and locale. Compare canonical objects and trees, not +unstable display text. + +### Roles and publication boundary + +Use distinct real app sessions, all in autopilot, for: + +1. **Planner:** discovers scope and writes the approved plan; never writes or + publishes repository changes. +2. **Executor:** implements only the approved plan and returns commit/evidence; + never pushes, creates/updates a PR or preview anchor, marks a PR ready, or + merges. +3. **Judge:** independently judges the executor's actual execution and evidence, + including a fresh diff-tag audit; never lands. +4. **Coordinator:** routes work, preserves durable evidence, requests explicit + user approval, and is the sole role allowed to publish or land. + +Delegated lanes do not prompt the user. They stop and return ambiguity or +failure to the coordinator. A PASS is not publication approval. + +### State and resume contract + +Persist state outside the repository: + +```text +discovered +backed-up +merge-paused +adjudicating +merge-committed +ports-committed +validated +judged +publication-approved +fork-pushed +preview-anchored +pr-created-or-updated +ready-approved +complete +``` + +For `stable-sync`, use `stable-merge-paused` and record the pinned stable-tip +SHA. Before every action: + +1. Read state and the current Git graph. +2. Reassert every completed state. +3. Resume at the first incomplete state. +4. Stop if persisted SHAs disagree with refs or unexplained files are present. +5. Never repeat a push, PR mutation, anchor mutation, or merge. + +Only one writer may mutate a branch/worktree or run a heavy build at a time. +Each live cmux/tmux surface has a unique lane/session name, a transcript, and an +ownership marker. Never send keys to an inherited pane. Quarantine ambiguous +panes and confirm old processes have exited before handing off ownership. + +Detect stale executors and races before accepting a handoff: compare the +executor's recorded branch, HEAD, base, target, worktree, and session identity to +live state. Reject results produced from a superseded baseline. Copy evidence to +coordinator-owned storage before archiving a dead or completed session; archive +only after no lane depends on its worktree, logs, or refs. + +## Steps + +### 1. Common preflight + +1. Assert a clean worktree, expected feature branch, exact HEAD, and no other + writer. +2. Fetch only needed refs: + + ```bash + git fetch origin + git fetch upstream main + git fetch facebook main -stable + ``` + +3. Resolve and record full SHAs for local HEAD, origin branch, `upstream/main`, + `facebook/main`, `facebook/-stable`, merge bases, and any PR + base/head. Record tree SHAs, ahead/behind counts, first-parent history, and a + decorated graph. +4. Store snapshots outside the repository. +5. Enable rerere repository-locally only: + + ```bash + git config --local rerere.enabled true + git config --local rerere.autoupdate false + ``` + + Rerere output is a candidate, never authorization to stage. +6. Create a local backup ref. A remote backup is a publication action and needs + explicit user approval through the coordinator. If a backup already exists, + require the exact recorded SHA. +7. Refuse a rewrite unless the base actually moved, the old base is an ancestor + of the new base, backup/evidence are durable, and the coordinator has the + required approval. Prefer normal/additive pushes; never use plain `--force`. + +### 2. Optional resolution engine: isolated Jujutsu v0.43 + +Jujutsu is optional. Use exactly an isolated, non-colocated jj v0.43 workspace; +never initialize jj in the canonical Git worktree or allow auto-snapshot to +mutate it. Git refs, commits, ordered merge parents, trees, and validation remain +authoritative. + +1. Import the exact Git objects into a disposable non-colocated workspace. +2. Record jj Change IDs and their imported Git commit/tree IDs. +3. Resolve by Change ID in focused changes. Avoid whole-file restores and + working-copy-wide resolution at semantic layer boundaries: either can absorb + unrelated changes or collapse reversible layers. +4. Compare jj's conflict set with Git's index conflict set. The sets may differ; + reconcile every path/hunk rather than assuming either representation is + complete. +5. Set a temporary export bookmark at the reviewed Change ID, export it to the + isolated workspace's Git store, and copy that exact full-SHA object to a + temporary ref in the canonical Git repository: + + ```bash + jj --repository "$JJ_WORKSPACE" bookmark set "export-" -r "" + jj --repository "$JJ_WORKSPACE" git export + ``` + +6. Verify the copied Git object: + + ```bash + EXPORTED_SHA=$(git rev-parse --verify "^{commit}") + git fsck --no-dangling "$EXPORTED_SHA" + git diff --exit-code "" "$EXPORTED_SHA^{tree}" + git rev-parse "$EXPORTED_SHA^1" "$EXPORTED_SHA^2" + ``` + +7. Move the preparation branch only after Git verifies the expected tree, + parent order, conflict absence, and Change-ID-to-Git-object map. The optional + engine's only accepted output is verified Git objects. + +### 3. Mode: `fork-merge` + +Compute the only valid upstream target: + +```bash +FACEBOOK_MAIN_SHA=$(git rev-parse --verify "facebook/main^{commit}") +STABLE_TIP_SHA=$(git rev-parse --verify "facebook/-stable^{commit}") +TARGET_SHA=$(git merge-base "$FACEBOOK_MAIN_SHA" "$STABLE_TIP_SHA") +test -n "$TARGET_SHA" +git merge-base --is-ancestor "$TARGET_SHA" "$STABLE_TIP_SHA" +``` + +Assert that `TARGET_SHA` is the upstream main commit where the stable line +forked, is not the stable tip, and is divergent from the Microsoft predecessor +when a real merge is expected. Pin it in state. + +Create `-merge` from `BASE_SHA` and run: + +```bash +git merge --no-ff "$TARGET_SHA" +``` + +Resolve mechanically and minimally: + +- adopt non-semantic upstream structure; +- preserve legitimate macOS behavior through narrow additive `[macOS]` clauses; +- do not select an entire semantic side when hunks have different provenance; +- avoid opportunistic cleanup; +- keep the merge focused on safe structural resolution; +- defer coherent cross-layer ports to named follow-up commits. + +Commit only after every index conflict and serialized marker is gone. Verify the +mechanical commit has exactly two ordered parents: + +```bash +MERGE_SHA=$(git rev-parse --verify "HEAD^{commit}") +test "$(git rev-list --parents -n 1 "$MERGE_SHA" | wc -w | tr -d ' ')" = 3 +test "$(git rev-parse "$MERGE_SHA^1")" = "$BASE_SHA" +test "$(git rev-parse "$MERGE_SHA^2")" = "$TARGET_SHA" +``` + +The stable tip must not be an ancestor: + +```bash +if git merge-base --is-ancestor "$STABLE_TIP_SHA" HEAD; then + echo "stable tip leaked into mainline" >&2 + exit 1 +fi +``` + +### 4. Mode: `stable-sync` + +Require the matching landed minor result. Resolve and pin the stable tip: + +```bash +MATCHING_BASE_SHA=$(git rev-parse --verify "^{commit}") +STABLE_TIP_SHA=$(git rev-parse --verify "facebook/-stable^{commit}") +git switch -c "/release" "$MATCHING_BASE_SHA" +git merge --no-ff "$STABLE_TIP_SHA" +``` + +If the remote stable branch moves, report the new full SHA and begin a new run; +never widen the current run. + +Use Changesets, not the obsolete `yarn nx release plan` flow: + +```bash +yarn change +yarn change:check +yarn changeset status --since="" +``` + +#### Prerelease lifecycle + +- Verify `.changeset/config.json`, public and private package versions, ignored + packages, exact `react-native` peer pins, and whether `.changeset/pre.json` + exists before doing anything. +- For an RC line, enter prerelease mode explicitly with + `yarn changeset pre enter rc` and record `pre.json`. The intended transition + is `rc.0` plus prerelease mode plus a patch Changeset to `rc.1`; inspect + `yarn changeset status` before materializing versions. +- Run `yarn changeset:version` at most once for the approved Changeset state. + That script already runs `yarn changeset version`, post-bumps native artifacts, + and updates the lockfile. Do not run raw `yarn changeset version` first or + otherwise double-version. +- Compare all public/private package versions, changelogs, native artifact + versions, and exact peer dependencies before and after materialization. +- Refuse an accidental final version, a duplicate bump, a broad peer range, or a + missing/private package transition. +- Keep `pre.json` for subsequent RCs. Run `yarn changeset pre exit` only for an + explicitly approved final release, inspect the planned final versions, + materialize once, and verify `pre.json` removal. Never infer that RC + completion authorizes a final. + +Verify the stable merge's parent 1 is `MATCHING_BASE_SHA` and parent 2 is the +pinned `STABLE_TIP_SHA`. + +### 5. Mode: `stack` + +For `..`: + +1. Discover and pin every exact Facebook fork point first. +2. Build each Microsoft `-merge` from the prior minor result. +3. Keep every Facebook stable tip out of cross-minor ancestry. +4. Do not start a later heavy writer until its predecessor has durable local + refs and coordinator-owned evidence. +5. Treat any preview anchor as optional publication infrastructure, never as + release truth. +6. After a predecessor changes or lands, recreate, retarget, revalidate, and + rejudge each downstream branch. + +### 6. Mode: `stack-recreate` + +Use after human review edits, focused PR landings, or a moved Microsoft base: + +```bash +OLD_BASE_SHA=$(git rev-parse --verify "^{commit}") +NEW_BASE_SHA=$(git rev-parse --verify "^{commit}") +git merge-base --is-ancestor "$OLD_BASE_SHA" "$NEW_BASE_SHA" +git rebase --rebase-merges --onto "$NEW_BASE_SHA" "$OLD_BASE_SHA" -merge +``` + +Inspect the generated todo before continuing. Git may try to replay +Facebook-side ancestry. The recreated mechanical root must still have the new +Microsoft base as parent 1 and the original pinned fork point as parent 2. If +necessary: + +1. Save the audited resolved tree and abort the invalid replay. +2. Recreate the mechanical root: + + ```bash + NEW_MERGE_SHA=$(printf '%s\n' "" | + git commit-tree "" \ + -p "$NEW_BASE_SHA" \ + -p "$TARGET_SHA") + ``` + +3. Replay only focused follow-ups: + + ```bash + git rebase --rebase-merges --empty=keep \ + --onto "$NEW_MERGE_SHA" "$OLD_MERGE_SHA" -merge + ``` + +Keep intentionally empty follow-ups when their fix is now upstream. Preserve the +old-to-new map. Rerun conflict provenance, diff tags, generated artifacts, +determinism, builds, evidence, and independent judgment for this execution. + +### 7. Mode: `focused-extraction` + +Extract a coherent change when it can land independently and make the large +merge smaller or reviewable: + +1. Identify the earliest valid Microsoft base, normally `main`. +2. Extract only the focused commit(s); do not copy the mechanical merge. +3. Preserve bilateral provenance, diff tags, tests, and a focused description. +4. Record the candidate branch/commit in merge state and evidence. +5. Do not push or open a PR; return the prepared local result to the coordinator. +6. After the focused change lands, recreate the merge so the conflict becomes + upstreamed or mechanical. Never duplicate the change in both histories. + +Good candidates include a new iOS/RN feature port, cross-layer API migration, +release/tooling fix, generator hardening, codegen path quoting, or a general +Hermes correction. + +### 8. Conflict evidence gate + +Count unique conflicted paths, index entries, and serialized conflict blocks +separately: + +```bash +git ls-files -u | cut -f2 | LC_ALL=C sort -u > conflicted-paths.txt +git ls-files -u | wc -l +wc -l < conflicted-paths.txt +git diff --name-only --diff-filter=U | LC_ALL=C sort -u +git status --porcelain=v1 +git grep -n -E '^(<<<<<<<|=======|>>>>>>>)( |$)' -- . || true +grep -c '^<<<<<<< ' "" +``` + +- The unique `git ls-files -u` path count is authoritative for index conflicts; + stage-entry count is not a path count. +- Count conflict hunks from one canonical serialized representation as the + number of opening markers, and retain the serialized file/hash with its Git + config, labels, command arguments, version, and locale. +- Raw conflict text/hashes are diagnostic only. Normalize paths, full SHAs, + labels, line endings, and locale before comparing runs, and retain both raw + and normalized hashes. +- Verify required terms are present and forbidden/stale terms are absent. + Presence-only checks miss bad combined resolutions. +- Reconcile every discrepancy among index paths, diff-filter output, jj + conflicts, rerere status, and serialized markers. + +Before staging each conflict, record bilateral provenance **per hunk**: + +- path and hunk identifier; +- upstream introducing full SHA, subject/PR, intent, and superseding commits; +- local macOS full SHA, subject/PR, intent, and current legitimacy; +- rerere candidate disposition; +- decision: upstream delta is authoritative because local is stale, preserve + legitimate macOS behavior on upstream structure, combine independent valid + changes, or stop; +- final basis and follow-up layer. + +Use path/hunk-aware `git log -p`, `git blame`, and rename-following history. A +tag is not provenance. Never choose `ours`, `theirs`, or a whole semantic file +when different hunks require different decisions. For modify/delete conflicts, +find the upstream replacement owner and map the local requirement there; never +resurrect a deleted file without current evidence. Audit rerere against index +stages 1/2/3 and stage accepted paths individually. + +### 9. Diff-tag gate + +Read `docsite/docs/contributing/diffs-with-upstream.md`. Audit each semantic +layer against its selected Microsoft base, not only the final combined diff. + +- Preserve inherited valid findings and their provenance across layers. +- Compute both the raw delta and a normalized NEW delta that removes moves, + formatting, generated churn, and already-inherited tagged fork differences. + Tag only genuinely new/retained fork behavior, not normalization noise. +- Use `// [macOS]` for a modified line, `[macOS` / `macOS]` around additions, + and a file-level marker near the top of macOS-only files, including `.mts` and + `.d.ts`. +- Audit multiline preprocessor expressions as one condition. Prefer the minimal + additive condition, such as adding `|| TARGET_OS_OSX` to the existing iOS + clause, rather than restructuring the entire branch. +- Apply documented shapes to iOS-only guards, mixed `iOS || macOS` conditions, + `#else` branches, and block endings. +- Search NEW additions for `TARGET_OS_OSX`, `RCTPlatform*`, `RCTUIKit`, AppKit, + `.macos.*`, and untagged macOS file patterns. Record justified exceptions. +- Remove a tag only when its fork difference genuinely disappeared or moved to + a documented new owner. + +Rerun the raw/normalized audit after the mechanical merge and after every +semantic, generated, Apple, Hermes, tooling, and CI layer. Executor and judge +each produce independent evidence; tag compliance is a publication blocker. + +### 10. Determinism gates + +#### Yarn + +- Preserve the baseline lockfile and package-manager version. Do not enable + global age-zero behavior or `YARN_ENABLE_HARDENED_MODE`, and do not perform a + full lock regeneration to solve a targeted tuple. +- Respect Yarn's package-age gate. If a required artifact is too new, record the + exact descriptor/resolution/checksum and wait or use the repository-approved + targeted mechanism; never disable the gate globally. +- Reconstruct only affected descriptors from the same baseline and record tuple + provenance: package, descriptor, locator, version, source/registry, checksum, + dependents, and why it changed. +- Run targeted lock generation twice from identical clean baselines and require + byte-identical `yarn.lock` hashes. Then run normal `yarn install --immutable`; + the normal immutable run is authoritative. +- Reject opportunistic upgrades, unexpected tuple churn, or baseline drift. + +#### Ruby, Bundler, and CocoaPods + +- Keep `Gemfile` and `Gemfile.lock` consistent; use the locked Bundler, Ruby, and + CocoaPods versions rather than a host default. +- Run pod generation from the same path shape and environment. Record podspec + source paths, pod checksums, lockfile hashes, and generated-project deltas. +- Treat path-derived podspec content, changing checksums, absolute build paths, + or an unlocked CocoaPods version as nondeterministic failures. +- Exercise the embedded + `packages/react-native/scripts/hermes/prepare-hermes-for-build.js` path and the + `prepare_command` in + `packages/react-native/sdks/hermes-engine/hermes-engine.podspec`, not a + hand-simulated substitute. + +#### Public C++ API + +- For release/stable generation, use the canonical Linux environment with + Doxygen 1.16.1 and Python 3.12. Do not regenerate with host macOS tools. +- Run the generator twice from the same clean input and require byte-identical + output. Compare against the expected public API snapshot and reject + truncation, path leakage, ordering drift, or partial/corrupt output. +- Skip this generator in the `fork-merge` workflow when the canonical upstream + workflow skips it; do not commit a host-generated replacement merely to make + the snapshot quiet. +- Keep `private/cxx-public-api` checks separate from the canonical release + Doxygen generator when both exist in the selected minor. + +#### Hermes + +- Verify the exact Hermes commit/version pins, host compiler, CMake version, and + explicit `CMAKE_BUILD_TYPE`; never infer build type from a reused directory. +- Use the path-independent podspec at + `packages/react-native/sdks/hermes-engine/hermes-engine.podspec`. Its + source/prebuilt choice, embedded prepare command, and package mapping must work + outside the repository's absolute path. +- Decide and record prebuilt versus source. Prebuilt validation checks archive + hashes, all required platform binaries, public headers, inspector headers, + module/header mappings, and podspec pins. Source validation checks the pinned + commit, host `hermesc`, target frameworks, and packaging. +- Treat absent inspector/public headers as a packaging failure, not an optional + omission. Do not paper over them with stale headers from another artifact. +- If source or exported headers change after an RC artifact was built or + published, generate fresh matching prebuilts and rerun packaging before any + publication. A prior green artifact is stale. + +### 11. Reversible history and review workflow + +Keep reviewable commits in order: + +1. mechanical ordered two-parent merge; +2. focused macOS API/type ports; +3. generated API snapshots; +4. Apple source/platform ports; +5. Hermes/toolchain compatibility; +6. narrowly scoped corrections; +7. CI fixes tied to distinct root causes. + +Do not amend or squash by default. Keep backups and evidence across recreation. +After human feedback, use `stack-recreate`, preserve coherent review layers, +rerun every downstream semantic gate, and obtain a fresh judge decision. + +Normal/additive publication is preferred. A history rewrite is exceptional and +requires explicit approval plus an exact lease: + +```bash +git push \ + --force-with-lease=refs/heads/: \ + origin +``` + +Never use plain `--force`; stop if the remote moved. + +### 12. Validation and CI + +Run focused checks first, then full gates in this order: + +1. immutable Yarn install, Changesets checks, constraints, format, lint, Jest, + and Flow as applicable; +2. build/generated types **before** legacy TypeScript: + + ```bash + yarn build-types + yarn test-generated-typescript + yarn test-typescript + ``` + +3. CocoaPods and SwiftPM manifests/generation; +4. public API and deterministic generators; +5. Hermes source/prebuilt/header packaging; +6. Apple platform builds and RNTester. + +The generated-types command validates the output of `build-types`; do not omit +that generation step or reverse the generated and legacy +`packages/react-native/types` checks. + +For Apple prebuilds, require the five release slices recorded for the target +release: iOS device, iOS simulator, macOS, visionOS device, and visionOS +simulator. Validate Mac Catalyst too when included by the selected release +configuration. Compose the XCFramework, verify every expected library and +architecture, and retain matching dSYMs. Run RNTester on the required iOS/macOS +architectures and old/new architecture matrix; do not substitute a packaging +success for product execution. + +Use a visible TTY with teed logs for long commands. Only one heavy writer/build +may run on a host at once. Diagnose CPU, memory, disk, simulator, runner, and +timeout saturation before labeling red as product failure. Distinguish: + +- **harness/infrastructure error:** no meaningful product step ran, runner or + simulator failed, host overloaded, or logs prove setup failure; +- **product failure:** a relevant compile, test, package, or runtime step ran + against the exact head and failed. + +Record exact head and toolchain provenance for both. Hosted CI is a fallback +only after explicit user approval through the coordinator; never push merely to +obtain compute. + +### 13. Evidence corpus and review body + +Before session archival, copy executor and judge evidence to a +coordinator-owned artifact directory. Include: + +- plan, prompts, state, refs, full-SHA graphs, Git config, and environment; +- raw and normalized conflict inventories/hashes; +- per-hunk bilateral provenance and decisions; +- per-layer raw/normalized diff-tag audits; +- old-to-new commit maps, deterministic two-run hashes, validation logs, and + exact-head proof; +- package/lock/pod/Hermes/prebuilt provenance; +- final diff, status, commit bundle, and judge verdict. + +Create a durable archive and Git bundle: + +```bash +tar -C "" -czf ".tar.gz" "" +shasum -a 256 ".tar.gz" > ".tar.gz.sha256" +git bundle create ".bundle" "" +shasum -a 256 ".bundle" > ".bundle.sha256" +``` + +Verify archives can be listed and the bundle verifies before deleting any +session/worktree. Keep artifacts out of the repository. + +Generate PR body text locally even when publication is not authorized. Preserve +both exact bytes and a normalized form. Normalize line endings to LF and define +whether the canonical body has exactly one trailing newline before hashing: + +```bash +perl -pi -e 's/\r\n?/\n/g' "" +printf '\n' >> "" +perl -0pi -e 's/\n+\z/\n/' "" +shasum -a 256 "" +``` + +If a PR already exists, fetch the live body bytes, normalize with the same +procedure, and compare both byte/hash forms. Update SHAs, links, conflict totals, +test evidence, and body hashes after final gates and any recreation. + +### 14. Focused mainline candidates + +Record each candidate as already on main, extracted locally, pending, rejected, +or obsolete. Do not silently reimplement something already present: + +- Changesets origin/base fallback; +- canonical C++ generator hardening; +- codegen path quoting; +- general Hermes resolution, podspec, or packaging fixes; +- `test-all`/CI build-types-before-legacy-TypeScript ordering; +- removal of obsolete `yarn nx release plan` documentation. + +Keep candidates out of the merge resolution unless required for coherent +behavior. Use `focused-extraction` when independent review is better. + +### 15. Publication controls + +Never push any ref, create or update a PR, create/delete a preview anchor, mark a +PR ready, or merge without explicit user approval obtained by the coordinator +for that exact action, destination, and SHA. Executor and judge do no +publication. Coordinator is the sole landing role. + +After approval, the coordinator still rechecks the exact judged SHA, remote +state, evidence hashes, and downstream dependencies. A changed SHA invalidates +the judgment and requires recreation/revalidation/rejudgment. Preview anchors +must be new additive refs, must never rewrite unrelated refs, and require +separate approval to delete. + +### 16. Final graph and completion gates + +For `fork-merge`, assert with full SHAs: + +```bash +test "$(git rev-parse "$MERGE_SHA^1")" = "$BASE_SHA" +test "$(git rev-parse "$MERGE_SHA^2")" = "$TARGET_SHA" +test "$(git merge-base "$BASE_SHA" HEAD)" = "$BASE_SHA" +git rev-list --left-right --count "$BASE_SHA...HEAD" +``` + +Require: + +- exactly one intended mechanical merge on first-parent history; +- exact ordered parents and no stable-tip ancestry; +- expected merge base and ahead/behind topology; +- clean index/worktree and no serialized conflict markers; +- reconciled conflict metrics and bilateral per-hunk decisions; +- every semantic layer's raw/normalized diff-tag audit; +- deterministic dependency, generator, pod, and Hermes results; +- required type, Apple slice, XCFramework/dSYM, and RNTester gates; +- fresh matching prebuilts after any post-RC source/header change; +- durable coordinator evidence, archive/hash/bundle verification; +- fresh independent judge PASS for the exact current SHA. + +For `stable-sync`, also require the pinned stable tip as parent 2, correct +Changesets prerelease/final state, exact peer pins, and proof that no later stable +commit drifted into the run. + +Stop rather than guess when: + +- graph, parent, target, ref, or state assertions fail; +- conventions or provenance are ambiguous; +- conflict sets or metrics do not reconcile; +- a local behavior has no owner after upstream deletion; +- diff-tag, determinism, packaging, build, or product validation fails; +- a harness failure cannot be separated from product red; +- source/header changes lack fresh matching prebuilts; +- another lane moved the branch, remote, PR, or evidence baseline; +- credentials would need weakening; +- publication approval is absent or does not match the exact action/SHA. + +Report final refs and parents, topology, conflict/decision totals, old-to-new +maps, validation logs, artifact hashes, judge state, and all blockers to the +coordinator. Stop before publication. diff --git a/.ai/index.md b/.ai/index.md index 74b69b6817a7..0272ea8123de 100644 --- a/.ai/index.md +++ b/.ai/index.md @@ -1,3 +1,8 @@ # AI Notes Use [Conventional Commits](https://www.conventionalcommits.org/) for PR titles. + +## Commands + +- [Backport](commands/backport.md) — backport feature commits to stable release branches. +- [Merge minor](commands/merge-minor.md) — prepare, recreate, and validate minor merge and stable-release branches. diff --git a/.claude/commands/merge-minor.md b/.claude/commands/merge-minor.md new file mode 100644 index 000000000000..38805b3dbdd5 --- /dev/null +++ b/.claude/commands/merge-minor.md @@ -0,0 +1,3 @@ +Follow the instructions in .ai/commands/merge-minor.md + +Minor / range: $ARGUMENTS diff --git a/.github/workflows/microsoft-npm-publish.yml b/.github/workflows/microsoft-npm-publish.yml index f6e9a5456834..f49bc7a28356 100644 --- a/.github/workflows/microsoft-npm-publish.yml +++ b/.github/workflows/microsoft-npm-publish.yml @@ -3,7 +3,7 @@ name: Publish to npm on: push: branches: - - "*-stable" + - '*-stable' concurrency: # Serialize release lines because they share the latest and next tags. @@ -36,7 +36,7 @@ jobs: - name: Setup toolchain uses: ./.github/actions/microsoft-setup-toolchain with: - node-version: "22" + node-version: '22' - name: Install dependencies run: yarn install --immutable diff --git a/.github/workflows/microsoft-pr.yml b/.github/workflows/microsoft-pr.yml index 906ce1fa52d6..71fab913b720 100644 --- a/.github/workflows/microsoft-pr.yml +++ b/.github/workflows/microsoft-pr.yml @@ -3,7 +3,15 @@ name: PR on: pull_request: types: [opened, synchronize, edited] - branches: ['main', '*-stable', 'release/*', '*-merge', 'review/**', 'saadnajmi/0-85-redbox2-merge'] + branches: + [ + 'main', + '*-stable', + 'release/*', + '*-merge', + 'review/**', + 'saadnajmi/0-85-redbox2-merge', + ] concurrency: # Ensure single build of a pull request. `main` should not be affected. diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 1cf2055b1644..f16740450ada 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> * * This file was generated by scripts/js-api/build-types/index.js. */ @@ -21,20 +21,18 @@ /* eslint-disable redundant-undefined/redundant-undefined */ +import type { FocusEvent as FocusEvent_2 } from "react-native" import type { HostInstance as HostInstance_2 } from "react-native" -import { ListRenderItem } from "@react-native-macos/virtualized-lists" -import { ListRenderItemInfo } from "@react-native-macos/virtualized-lists" -import { ListViewToken } from "@react-native-macos/virtualized-lists" +import type { LayoutChangeEvent as LayoutChangeEvent_2 } from "react-native" +import type { LayoutRectangle as LayoutRectangle_2 } from "react-native" import type { PublicRootInstance as PublicRootInstance_2 } from "react-native" import type { PublicTextInstance as PublicTextInstance_2 } from "react-native" import * as React from "react" -import { ScrollToLocationParamsType } from "@react-native-macos/virtualized-lists" -import { SectionBase } from "@react-native-macos/virtualized-lists" -import type { SectionData as SectionListData } from "@react-native-macos/virtualized-lists" -import { Separators } from "@react-native-macos/virtualized-lists" -import { VirtualizedListProps } from "@react-native-macos/virtualized-lists" -import VirtualizedLists from "@react-native-macos/virtualized-lists" -import { VirtualizedSectionListProps } from "@react-native-macos/virtualized-lists" +import type { ScrollResponderType as ScrollResponderType_2 } from "react-native" +import { ScrollView as ScrollView_2 } from "react-native" +import type { ScrollViewProps as ScrollViewProps_2 } from "react-native" +import type { StyleProp as StyleProp_2 } from "react-native" +import type { ViewStyle as ViewStyle_2 } from "react-native" declare const $$AnimatedFlatList: ( props: Omit>, "ref"> & { ref?: React.Ref> @@ -89,6 +87,14 @@ declare const $$AnimatedView: AnimatedComponentType< React.ComponentRef > declare const $$flattenStyle: typeof flattenStyle_default +declare const $$index: { + keyExtractor: typeof keyExtractor + get FillRateHelper(): FillRateHelperT + get ViewabilityHelper(): ViewabilityHelperT + get VirtualizedList(): VirtualizedListT + get VirtualizedListContextResetter(): VirtualizedListContextResetterT + get VirtualizedSectionList(): AnyVirtualizedSectionList +} declare const $$NativeDeviceInfo: typeof NativeDeviceInfo_default declare const $$ReactFabric: typeof ReactFabric_default declare const $$ScrollViewContext: typeof ScrollViewContext_default @@ -536,8 +542,23 @@ declare const Vibration_default: { declare const View: typeof View_default declare const VirtualizedList: typeof VirtualizedListComponent_default declare const VirtualizedListComponent_default: VirtualizedListType +declare const VirtualizedListContext: React.Context declare const VirtualizedSectionList: typeof VirtualizedSectionList_default declare const VirtualizedSectionList_default: VirtualizedSectionListType +declare const VirtualizedSectionListComponent_default: < + ItemT, + SectionT extends SectionBase< + ItemT, + DefaultVirtualizedSectionT + > = DefaultVirtualizedSectionT, +>( + props: Omit, "ref"> & { + ref?: React.Ref<{ + getListRef(): undefined | VirtualizedList_default + scrollToLocation(params: ScrollToLocationParamsType): void + }> + }, +) => React.ReactNode declare type ____BlendMode_Internal = | "color-burn" | "color-dodge" @@ -986,6 +1007,7 @@ declare type $$AnimatedSectionList = typeof $$AnimatedSectionList declare type $$AnimatedText = typeof $$AnimatedText declare type $$AnimatedView = typeof $$AnimatedView declare type $$flattenStyle = typeof $$flattenStyle +declare type $$index = typeof $$index declare type $$NativeDeviceInfo = typeof $$NativeDeviceInfo declare type $$ReactFabric = typeof $$ReactFabric declare type $$ScrollViewContext = typeof $$ScrollViewContext @@ -1585,6 +1607,8 @@ declare type AnimationConfig = { readonly useNativeDriver: boolean } declare type AnyAttributeType = AttributeType +declare type AnyVirtualizedSectionList = + typeof VirtualizedSectionListComponent_default declare type AppConfig = { appKey: string component?: ComponentProvider @@ -1773,6 +1797,40 @@ declare interface ButtonProps { } declare function cancelHeadlessTask(taskId: number, taskKey: string): void declare type Category = string +declare type CellMetricProps = { + data: VirtualizedListProps["data"] + getItem: VirtualizedListProps["getItem"] + getItemCount: VirtualizedListProps["getItemCount"] + getItemLayout?: VirtualizedListProps["getItemLayout"] + keyExtractor?: VirtualizedListProps["keyExtractor"] +} +declare type CellMetrics = { + index: number + isMounted: boolean + length: number + offset: number +} +declare type CellRegion = { + first: number + isSpacer: boolean + last: number +} +declare type CellRendererProps = { + readonly cellKey: string + readonly children: React.ReactNode + readonly index: number + readonly item: ItemT + readonly style: StyleProp_2 + readonly onFocusCapture?: (event: FocusEvent_2) => void + readonly onLayout?: (event: LayoutChangeEvent_2) => void +} +declare class CellRenderMask { + addCells(cells: { first: number; last: number }): void + constructor(numCells: number) + enumerateRegions(): ReadonlyArray + equals(other: CellRenderMask): boolean + numCells(): number +} declare type Clipboard = typeof Clipboard declare type codegenNativeCommands = typeof codegenNativeCommands declare function codegenNativeCommands_default( @@ -1823,6 +1881,28 @@ declare function configureNext( onAnimationDidFail?: OnAnimationDidFailCallback, ): void declare type ContentAvailable = 1 | null | void +declare type Context = { + readonly cellKey: string | undefined + readonly horizontal: boolean | undefined + readonly getOutermostParentListRef: () => VirtualizedList_default + readonly getScrollMetrics: () => { + contentLength: number + dOffset: number + dt: number + offset: number + timestamp: number + velocity: number + visibleLength: number + zoomScale: number + } + readonly registerAsNestedChild: ($$PARAM_0$$: { + cellKey: string + ref: VirtualizedList_default + }) => void + readonly unregisterAsNestedChild: ($$PARAM_0$$: { + ref: VirtualizedList_default + }) => void +} declare function counterEvent(eventName: EventName, value: number): void declare type create = typeof create declare type createAnimatedComponent = typeof createAnimatedComponent @@ -1945,6 +2025,10 @@ declare type DefaultSectionT = { [key: string]: any } declare type DefaultTypes = boolean | number | ReadonlyArray | string +declare type DefaultVirtualizedSectionT = { + [key: string]: any + data: any +} declare type delay = typeof delay declare interface DEPRECATED_RCTExport { readonly getConstants?: () => {} @@ -2259,6 +2343,34 @@ declare type FetchResult = { NoData: "UIBackgroundFetchResultNoData" ResultFailed: "UIBackgroundFetchResultFailed" } +declare class FillRateHelper_default { + activate(): void + static addListener(callback: ($$PARAM_0$$: FillRateInfo) => void): { + remove: () => void + } + computeBlankness( + props: CellMetricProps & { + initialNumToRender?: number + }, + cellsAroundViewport: { + first: number + last: number + }, + scrollMetrics: { + dOffset: number + offset: number + velocity: number + visibleLength: number + }, + ): number + constructor(listMetrics: ListMetricsAggregator_default) + deactivateAndFlush(): void + enabled(): boolean + static setMinSampleCount(minSampleCount: number): void + static setSampleRate(sampleRate: number): void +} +declare type FillRateHelperT = typeof FillRateHelper_default +declare type FillRateInfo = Info declare type FilterFunction = | { blur: number | string @@ -2716,6 +2828,18 @@ declare type IndeterminateProgressBarAndroidStyleAttrProp = { | "SmallInverse" } declare type IndicatorSize = "large" | "small" | number +declare class Info { + any_blank_count: number + any_blank_ms: number + any_blank_speed_sum: number + mostly_blank_count: number + mostly_blank_ms: number + pixels_blank: number + pixels_sampled: number + pixels_scrolled: number + sample_count: number + total_time_spent: number +} declare type InnerViewInstance = React.ComponentRef declare type InputAccessoryView = typeof InputAccessoryView declare interface InputAccessoryViewProps { @@ -2833,6 +2957,7 @@ declare interface IPerformanceLogger { stopTimespan(key: string, timestamp?: number, extras?: Extras): void } declare function isEnabled(): boolean +declare type Item = any declare type Keyboard = typeof Keyboard declare class KeyboardAvoidingView extends React.Component< KeyboardAvoidingViewProps, @@ -2948,6 +3073,7 @@ declare type KeyEventProps = { readonly onKeyUp?: (event: KeyUpEvent) => void readonly onKeyUpCapture?: (event: KeyUpEvent) => void } +declare function keyExtractor(item: any, index: number): string declare type KeysOfUnion = T extends any ? keyof T : never declare type KeyUpEvent = NativeSyntheticEvent declare type LayoutAnimation = typeof LayoutAnimation @@ -3030,6 +3156,57 @@ declare class LinkingImpl extends NativeEventEmitter { }>, ): Promise } +declare class ListMetricsAggregator_default { + cartesianOffset(flowRelativeOffset: number): number + flowRelativeOffset( + layout: LayoutRectangle_2, + referenceContentLength?: null | number | undefined, + ): number + getAverageCellLength(): number + getCellMetrics( + index: number, + props: CellMetricProps, + ): CellMetrics | null | undefined + getCellMetricsApprox(index: number, props: CellMetricProps): CellMetrics + getCellOffsetApprox(index: number, props: CellMetricProps): number + getContentLength(): number + getHighestMeasuredCellIndex(): number + hasContentLength(): boolean + notifyCellLayout($$PARAM_0$$: { + cellIndex: number + cellKey: string + layout: LayoutRectangle_2 + orientation: ListOrientation + }): boolean + notifyCellUnmounted(cellKey: string): void + notifyListContentLayout($$PARAM_0$$: { + layout: { + readonly height: number + readonly width: number + } + orientation: ListOrientation + }): void +} +declare type ListOrientation = { + horizontal: boolean + rtl: boolean +} +declare type ListRenderItem = ( + info: ListRenderItemInfo, +) => React.ReactNode +declare type ListRenderItemInfo = { + index: number + isSelected: boolean | undefined + item: ItemT + separators: Separators +} +declare type ListViewToken = { + index: number | undefined + isViewable: boolean + item: any + key: string + section?: any +} declare type LogBox = typeof LogBox declare type LogData = { readonly category: Category @@ -3433,6 +3610,79 @@ declare type OptionalSectionListProps = { removeClippedSubviews?: boolean renderItem?: SectionListRenderItem } +declare type OptionalVirtualizedListProps = { + CellRendererComponent?: React.ComponentType> + debug?: boolean + disableVirtualization?: boolean + extraData?: any + horizontal?: boolean + initialNumToRender?: number + initialScrollIndex?: number + inverted?: boolean + ItemSeparatorComponent?: React.ComponentType | React.JSX.Element + keyExtractor?: (item: Item, index: number) => string + ListEmptyComponent?: React.ComponentType | React.JSX.Element + ListFooterComponent?: React.ComponentType | React.JSX.Element + ListFooterComponentStyle?: StyleProp_2 + ListHeaderComponent?: React.ComponentType | React.JSX.Element + ListHeaderComponentStyle?: StyleProp_2 + ListItemComponent?: React.ComponentType | React.JSX.Element + maxToRenderPerBatch?: number + onEndReached?: (info: { distanceFromEnd: number }) => void + onEndReachedThreshold?: number + onRefresh?: () => void + onScrollToIndexFailed?: (info: { + averageItemLength: number + highestMeasuredFrameIndex: number + index: number + }) => void + onStartReached?: (info: { distanceFromStart: number }) => void + onStartReachedThreshold?: number + onViewableItemsChanged?: (info: { + changed: Array + viewableItems: Array + }) => void + persistentScrollbar?: boolean + progressViewOffset?: number + refreshControl?: React.JSX.Element + refreshing?: boolean + removeClippedSubviews?: boolean + renderItem?: ListRenderItem + updateCellsBatchingPeriod?: number + viewabilityConfig?: ViewabilityConfig + viewabilityConfigCallbackPairs?: Array + windowSize?: number + getItemLayout?: ( + data: any, + index: number, + ) => { + index: number + length: number + offset: number + } + renderScrollComponent?: (props: ScrollViewProps_2) => React.JSX.Element +} +declare type OptionalVirtualizedSectionListProps< + ItemT, + SectionT = DefaultVirtualizedSectionT, +> = { + onEndReached?: ($$PARAM_0$$: { distanceFromEnd: number }) => void + renderSectionFooter?: (info: { section: SectionT }) => null | React.ReactNode + renderSectionHeader?: (info: { section: SectionT }) => null | React.ReactNode + SectionSeparatorComponent?: React.ComponentType + stickySectionHeadersEnabled?: boolean + renderItem?: (info: { + index: number + isSelected: boolean | undefined + item: ItemT + section: SectionT + separators: { + highlight: () => void + unhighlight: () => void + updateProps: (select: "leading" | "trailing", newProps: Object) => void + } + }) => null | React.ReactNode +} declare type OrientationChangeEvent = { readonly orientation: "landscape" | "portrait" } @@ -4186,6 +4436,17 @@ declare type RequiredFlatListProps = { declare type RequiredSectionListProps = { sections: ReadonlyArray> } +declare type RequiredVirtualizedListProps = { + data?: any + getItem: (data: any, index: number) => Item | undefined + getItemCount: (data: any) => number +} +declare type RequiredVirtualizedSectionListProps< + ItemT, + SectionT = DefaultVirtualizedSectionT, +> = { + sections: ReadonlyArray> +} declare type requireNativeComponent = typeof requireNativeComponent declare type ResolvedAssetSource = { readonly height: number | undefined @@ -4331,6 +4592,13 @@ declare type ScheduleLocalNotificationDetails = } declare type ScrollEvent = NativeSyntheticEvent declare type ScrollResponderType = ScrollViewImperativeMethods +declare type ScrollToLocationParamsType = { + animated?: boolean + itemIndex: number + sectionIndex: number + viewOffset?: number + viewPosition?: number +} declare type ScrollView = typeof ScrollView declare type ScrollViewBaseProps = { readonly children?: React.ReactNode @@ -4480,6 +4748,28 @@ declare type ScrollViewStickyHeaderProps = { readonly scrollViewHeight: number | undefined readonly onLayout: (event: LayoutChangeEvent) => void } +declare type SectionBase< + SectionItemT, + SectionT = DefaultVirtualizedSectionT, +> = { + data: ReadonlyArray + ItemSeparatorComponent?: React.ComponentType | React.JSX.Element + key?: string + renderItem?: (info: { + index: number + item: SectionItemT + section: SectionListData + separators: { + highlight: () => void + unhighlight: () => void + updateProps: (select: "leading" | "trailing", newProps: Object) => void + } + }) => null | React.JSX.Element + keyExtractor?: ( + item: SectionItemT | undefined, + index?: number | undefined, + ) => string +} declare class SectionList< ItemT = any, SectionT = DefaultSectionT, @@ -4493,6 +4783,13 @@ declare class SectionList< scrollToLocation(params: ScrollToLocationParamsType): void setNativeProps(props: Object): void } +declare type SectionListData< + SectionItemT, + SectionT = DefaultVirtualizedSectionT, +> = + | (Readonly> & SectionT) + | (SectionBase & SectionT) + | SectionT declare type SectionListInstance = SectionList declare interface SectionListProps extends Readonly< @@ -4520,13 +4817,18 @@ declare type SectionListRenderItem = ( declare type SectionListRenderItemInfo< ItemT, SectionT = DefaultSectionT, -> = Omit, "section"> & { +> = ListRenderItemInfo & { section: SectionListData } declare type Selection = { readonly end: number readonly start: number } +declare type Separators = { + highlight: () => void + unhighlight: () => void + updateProps: (select: "leading" | "trailing", newProps: Object) => void +} declare type sequence = typeof sequence declare function setColorScheme(colorScheme: ColorSchemeOverride): void declare function setComponentProviderInstrumentationHook( @@ -4767,6 +5069,35 @@ declare function startHeadlessTask( taskKey: string, data: any, ): void +declare type State = { + cellsAroundViewport: { + first: number + last: number + } + firstVisibleItemKey: string | undefined + pendingScrollUpdateCount: number + renderMask: CellRenderMask + selectedRowIndex: number +} +declare class StateSafePureComponent_default< + Props, + State extends {}, +> extends React.PureComponent { + constructor(props: Props) + setState( + partialState: + | ( + | (( + $$PARAM_0$$: State, + $$PARAM_1$$: Props, + ) => null | Pick | undefined) + | Pick + ) + | null + | undefined, + callback?: () => unknown, + ): void +} declare class StatusBar extends React.Component { static currentHeight: null | number | undefined componentDidMount(): void @@ -5571,6 +5902,55 @@ declare function View_default( ref?: React.Ref }, ): React.ReactNode +declare type ViewabilityConfig = { + readonly itemVisiblePercentThreshold?: number + readonly minimumViewTime?: number + readonly viewAreaCoveragePercentThreshold?: number + readonly waitForInteraction?: boolean +} +declare type ViewabilityConfigCallbackPair = { + viewabilityConfig: ViewabilityConfig + onViewableItemsChanged: (info: { + changed: Array + viewableItems: Array + }) => void +} +declare class ViewabilityHelper_default { + computeViewableItems( + props: CellMetricProps, + scrollOffset: number, + viewportHeight: number, + listMetrics: ListMetricsAggregator_default, + renderRange?: { + first: number + last: number + }, + ): Array + constructor(config?: ViewabilityConfig) + dispose(): void + onUpdate( + props: CellMetricProps, + scrollOffset: number, + viewportHeight: number, + listMetrics: ListMetricsAggregator_default, + createViewToken: ( + index: number, + isViewable: boolean, + props: CellMetricProps, + ) => ListViewToken, + onViewableItemsChanged: ($$PARAM_0$$: { + changed: Array + viewableItems: Array + }) => void, + renderRange?: { + first: number + last: number + }, + ): void + recordInteraction(): void + resetViewableIndices(): void +} +declare type ViewabilityHelperT = typeof ViewabilityHelper_default declare type ViewBaseProps = { readonly children?: React.ReactNode readonly collapsable?: boolean @@ -5651,13 +6031,136 @@ declare type ViewPropsIOS = { declare type ViewStyle = ____ViewStyle_Internal declare type ViewStyleProp = ____ViewStyleProp_Internal declare type VirtualizedList = typeof VirtualizedList +declare class VirtualizedList_default extends StateSafePureComponent_default< + VirtualizedListProps, + State +> { + static contextType: typeof VirtualizedListContext + state: State + componentDidMount(): void + componentDidUpdate(prevProps: VirtualizedListProps): void + componentWillUnmount(): void + constructor(props: VirtualizedListProps) + ensureItemAtIndexIsVisible(rowIndex: number): void + flashScrollIndicators(): void + static getDerivedStateFromProps( + newProps: VirtualizedListProps, + prevState: State, + ): State + getScrollableNode(): null | number | undefined + getScrollRef(): null | React.ComponentRef | undefined + getScrollResponder(): null | ScrollResponderType_2 | undefined + hasMore(): boolean + measureLayoutRelativeToContainingList(): void + recordInteraction(): void + render(): React.ReactNode + scrollToEnd( + params?: + | null + | undefined + | { + animated?: boolean + }, + ): void + scrollToIndex(params: { + animated?: boolean + index: number + viewOffset?: number + viewPosition?: number + }): any + scrollToItem(params: { + animated?: boolean + item: Item + viewOffset?: number + viewPosition?: number + }): void + scrollToOffset(params: { animated?: boolean; offset: number }): void + selectRowAtIndex(rowIndex: number): void + setNativeProps(props: Object): void +} +declare type VirtualizedListContext = typeof VirtualizedListContext +declare function VirtualizedListContextResetter($$PARAM_0$$: { + children: React.ReactNode +}): React.ReactNode +declare type VirtualizedListContextResetterT = + typeof VirtualizedListContextResetter declare type VirtualizedListInstance = React.ComponentRef -declare type VirtualizedListType = typeof VirtualizedLists.VirtualizedList +declare type VirtualizedListMacOSProps = { + enableSelectionOnKeyPress?: boolean + initialSelectedIndex?: number + onSelectionChanged?: (info: { + item: Item | undefined + newSelection: number + previousSelection: number + }) => void + onSelectionEntered?: (item: Item | undefined) => void + rowIndex?: number + sectionIndex?: number +} +declare type VirtualizedListProps = Omit< + ScrollViewProps_2, + | "data" + | "getItem" + | "getItemCount" + | "enableSelectionOnKeyPress" + | "initialSelectedIndex" + | "onSelectionChanged" + | "onSelectionEntered" + | "rowIndex" + | "sectionIndex" + | "CellRendererComponent" + | "debug" + | "disableVirtualization" + | "extraData" + | "getItemLayout" + | "horizontal" + | "initialNumToRender" + | "initialScrollIndex" + | "inverted" + | "ItemSeparatorComponent" + | "keyExtractor" + | "ListEmptyComponent" + | "ListFooterComponent" + | "ListFooterComponentStyle" + | "ListHeaderComponent" + | "ListHeaderComponentStyle" + | "ListItemComponent" + | "maxToRenderPerBatch" + | "onEndReached" + | "onEndReachedThreshold" + | "onRefresh" + | "onScrollToIndexFailed" + | "onStartReached" + | "onStartReachedThreshold" + | "onViewableItemsChanged" + | "persistentScrollbar" + | "progressViewOffset" + | "refreshControl" + | "refreshing" + | "removeClippedSubviews" + | "renderItem" + | "renderScrollComponent" + | "updateCellsBatchingPeriod" + | "viewabilityConfig" + | "viewabilityConfigCallbackPairs" + | "windowSize" + | never +> & + RequiredVirtualizedListProps & + OptionalVirtualizedListProps & + VirtualizedListMacOSProps +declare type VirtualizedListT = typeof VirtualizedList_default +declare type VirtualizedListType = typeof $$index.VirtualizedList declare type VirtualizedSectionList = typeof VirtualizedSectionList declare type VirtualizedSectionListInstance = React.ComponentRef -declare type VirtualizedSectionListType = - typeof VirtualizedLists.VirtualizedSectionList +declare type VirtualizedSectionListProps< + ItemT, + SectionT = DefaultVirtualizedSectionT, +> = RequiredVirtualizedSectionListProps & + OptionalVirtualizedSectionListProps & + Omit +declare type VirtualizedSectionListType = typeof $$index.VirtualizedSectionList declare enum VirtualViewMode { Hidden = 2, Prerender = 1, @@ -5775,7 +6278,7 @@ export { AlertOptions, // 39b16cfa AlertType, // 5ab91217 AndroidKeyboardEvent, // e03becc8 - Animated, // be5ea01d + Animated, // 577c062d AppConfig, // 35c0ca70 AppRegistry, // 5ee0a63b AppState, // 12012be5 @@ -5830,9 +6333,9 @@ export { EventSubscription, // b8d084aa ExtendedExceptionData, // 5a6ccf5a FilterFunction, // bf24c0e3 - FlatList, // baec8ab3 - FlatListInstance, // f892502d - FlatListProps, // fb158bc8 + FlatList, // f7696760 + FlatListInstance, // 73f5c9ab + FlatListProps, // 4959f314 FocusEvent, // 850f1517 FontVariant, // 7c7558bb GestureResponderEvent, // 3bd4697e @@ -5890,9 +6393,9 @@ export { LayoutConformanceProps, // 055f03b8 LayoutRectangle, // 6601b294 Linking, // 9a6a174d - ListRenderItem, - ListRenderItemInfo, - ListViewToken, + ListRenderItem, // 3ba527db + ListRenderItemInfo, // d21a2b9b + ListViewToken, // 833d3481 LogBox, // 94d278f1 LogData, // e68f7019 MeasureInWindowOnSuccessCallback, // a285f598 @@ -5963,7 +6466,7 @@ export { ReturnKeyTypeOptions, // afd47ba3 Role, // af7b889d RootTag, // 3cd10504 - RootTagContext, // cc287c11 + RootTagContext, // 38bfc8f6 RootViewStyleProvider, // 6a15dcfc Runnable, // 594dd93a Runnables, // 4367c557 @@ -5972,22 +6475,22 @@ export { ScaledSize, // 07e417c7 ScrollEvent, // 10f01ee3 ScrollResponderType, // 02f30132 - ScrollToLocationParamsType, - ScrollView, // fcdcd27c + ScrollToLocationParamsType, // d7ecdad1 + ScrollView, // f7771307 ScrollViewImperativeMethods, // 63083e1a ScrollViewInstance, // 4bdb26a9 ScrollViewProps, // 11071735 ScrollViewPropsAndroid, // 44210553 ScrollViewPropsIOS, // 19a1147f ScrollViewScrollToOptions, // 3313411e - SectionBase, - SectionList, // 58abd791 - SectionListData, - SectionListInstance, // 5faca954 - SectionListProps, // 6061d1b8 - SectionListRenderItem, // c118edfb - SectionListRenderItemInfo, // bd038703 - Separators, + SectionBase, // dca83594 + SectionList, // efd5a5bc + SectionListData, // e0d79987 + SectionListInstance, // ef0e1831 + SectionListProps, // 3a95bf12 + SectionListRenderItem, // 75136fcc + SectionListRenderItemInfo, // 9d129607 + Separators, // 6a45f7e3 Settings, // 2be0c61e Share, // e4591b32 ShareAction, // ead1004a @@ -6013,7 +6516,7 @@ export { TaskProvider, // 266dedf2 Text, // c0e9e9ee TextContentType, // 239b3ecc - TextInput, // 0632b08e + TextInput, // 5211e3df TextInputAndroidProps, // 7109938a TextInputBlurEvent, // b77af40e TextInputChangeEvent, // f55eef98 @@ -6056,12 +6559,12 @@ export { ViewPropsIOS, // 58ee19bf ViewStyle, // 2fc81116 VirtualViewMode, // 6be59722 - VirtualizedList, // d4e15eaa - VirtualizedListInstance, // dcba9753 - VirtualizedListProps, - VirtualizedSectionList, // 486a3a9d - VirtualizedSectionListInstance, // b8db2acd - VirtualizedSectionListProps, + VirtualizedList, // 68c7345e + VirtualizedListInstance, // 423ee7c0 + VirtualizedListProps, // e424164d + VirtualizedSectionList, // 9fd9cd61 + VirtualizedSectionListInstance, // 12b706d5 + VirtualizedSectionListProps, // 965fd9c0 WrapperComponentProvider, // 4b8c7962 codegenNativeCommands, // 628a7c0a codegenNativeComponent, // 32a1bca6 diff --git a/packages/react-native/scripts/ios-prebuild/__tests__/hermes-test.js b/packages/react-native/scripts/ios-prebuild/__tests__/hermes-test.js index aeac276d1778..ddfedc6be480 100644 --- a/packages/react-native/scripts/ios-prebuild/__tests__/hermes-test.js +++ b/packages/react-native/scripts/ios-prebuild/__tests__/hermes-test.js @@ -359,7 +359,9 @@ test('the cache respects the single pin and flavor but ignores the obsolete flag execFileSync.mockClear(); await prepareHermesArtifactsAsync('0.83.1', 'Debug'); expect(global.fetch).not.toHaveBeenCalled(); - expect(execFileSync.mock.calls.map(([command]) => command)).toEqual(['plutil']); + expect(execFileSync.mock.calls.map(([command]) => command)).toEqual([ + 'plutil', + ]); properties = 'HERMES_VERSION_NAME=234.5.68\nHERMES_V1_VERSION_NAME=123.4.56'; await prepareHermesArtifactsAsync('0.83.1', 'Debug'); expect(global.fetch).toHaveBeenCalledWith(releaseUrl('234.5.68')); @@ -370,7 +372,9 @@ test('the cache respects the single pin and flavor but ignores the obsolete flag process.env.RCT_HERMES_V1_ENABLED = '0'; await prepareHermesArtifactsAsync('0.83.1', 'Release'); expect(global.fetch).not.toHaveBeenCalled(); - expect(execFileSync.mock.calls.map(([command]) => command)).toEqual(['plutil']); + expect(execFileSync.mock.calls.map(([command]) => command)).toEqual([ + 'plutil', + ]); }); test('unavailable artifacts fail without an npm or source fallback', async () => { diff --git a/packages/react-native/scripts/ios-prebuild/__tests__/hermes-version-test.js b/packages/react-native/scripts/ios-prebuild/__tests__/hermes-version-test.js index 7957515ad02a..a65224451638 100644 --- a/packages/react-native/scripts/ios-prebuild/__tests__/hermes-version-test.js +++ b/packages/react-native/scripts/ios-prebuild/__tests__/hermes-version-test.js @@ -149,8 +149,8 @@ test('the default runtime, compiler, and source tag versions agree', () => { const previous = process.env.RCT_HERMES_V1_ENABLED; try { delete process.env.RCT_HERMES_V1_ENABLED; - // CI and prebuild use V1 by default; the shared helper defaults to legacy. - const {version, tagFile} = readHermesMetadata('v1-default'); + // 0.87 uses a single V1 pin; the shared helper defaults to legacy. + const {version, tagFile} = readHermesMetadata('single'); const {dependencies} = require('../../../package.json'); expect(dependencies['hermes-compiler']).toBe(version); const tag = fs diff --git a/scripts/js-api/build-types/buildApiSnapshot.js b/scripts/js-api/build-types/buildApiSnapshot.js index e60d756c57a8..cbbe5b4fbe64 100644 --- a/scripts/js-api/build-types/buildApiSnapshot.js +++ b/scripts/js-api/build-types/buildApiSnapshot.js @@ -254,7 +254,7 @@ async function rewriteLocalImports( async function getProcessedSnapshotResult( tempDirectory: string, options: BuildApiSnapshotOptions, - packages: $ReadOnlyArray<{directory: string, name: string}>, + packages: ReadonlyArray<{directory: string, name: string}>, ): Promise { const rollupPath = path.join( tempDirectory, diff --git a/scripts/js-api/build-types/transforms/typescript/canonicalizeLocalPackageImports.js b/scripts/js-api/build-types/transforms/typescript/canonicalizeLocalPackageImports.js index 9c97ce7f8118..2a71455d03f7 100644 --- a/scripts/js-api/build-types/transforms/typescript/canonicalizeLocalPackageImports.js +++ b/scripts/js-api/build-types/transforms/typescript/canonicalizeLocalPackageImports.js @@ -18,7 +18,7 @@ import type { function canonicalizeSource( source: string, - packageNames: $ReadOnlyArray, + packageNames: ReadonlyArray, ): string { if (!source.startsWith('./') && !source.startsWith('../')) { return source; @@ -37,8 +37,8 @@ function canonicalizeSource( } function canonicalizeLocalPackageImports( - packageNames: $ReadOnlyArray, -): PluginObj { + packageNames: ReadonlyArray, +): PluginObj { function canonicalizeNodeSource( nodePath: NodePath< ExportAllDeclaration | ExportNamedDeclaration | ImportDeclaration,