Compare commits

..
2511 changed files with 43377 additions and 65597 deletions
+9
View File
@@ -9,3 +9,12 @@ end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
[*.gradle]
indent_size = 4
[*.kts]
indent_size = 4
[BUCK]
indent_size = 4
+7 -1
View File
@@ -75,6 +75,12 @@ module.system.haste.module_ref_prefix=m#
react.runtime=automatic
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_type=$FlowFixMeEmpty
ban_spread_key_props=true
[lints]
@@ -98,4 +104,4 @@ untyped-import
untyped-type-import
[version]
^0.281.0
^0.274.2
@@ -1,6 +1,6 @@
name: 🔍 Debugger - Bug Report
description: Report a bug with React Native DevTools and the New Debugger
labels: ["Needs: Triage :mag:", "Debugging"]
labels: ["Needs: Triage :mag:", "Debugger"]
body:
- type: markdown
+12 -6
View File
@@ -4,6 +4,9 @@ inputs:
release-type:
required: true
description: The type of release we are building. It could be nightly, release or dry-run
run-e2e-tests:
default: 'false'
description: If we need to build to run E2E tests. If yes, we need to build also x86.
gradle-cache-encryption-key:
description: "The encryption key needed to store the Gradle Configuration cache"
runs:
@@ -28,11 +31,10 @@ runs:
uses: actions/cache/restore@v4
with:
path: /github/home/.cache/ccache
key: v2-ccache-android-${{ github.job }}-${{ github.ref }}-${{ hashFiles('packages/react-native/ReactAndroid/**/*.cpp', 'packages/react-native/ReactAndroid/**/*.h', 'packages/react-native/ReactCommon/**/*.cpp', 'packages/react-native/ReactAndroid/**/CMakeLists.txt', 'packages/react-native/ReactCommon/**/CMakeLists.txt') }}
key: v1-ccache-android-${{ github.job }}-${{ github.ref }}
restore-keys: |
v2-ccache-android-${{ github.job }}-${{ github.ref }}-
v2-ccache-android-${{ github.job }}-
v2-ccache-android-
v1-ccache-android-${{ github.job }}-
v1-ccache-android-
- name: Show ccache stats
shell: bash
run: ccache -s -v
@@ -41,7 +43,11 @@ runs:
run: |
if [[ "${{ inputs.release-type }}" == "dry-run" ]]; then
# dry-run: we only build ARM64 to save time/resources. For release/nightlies the default is to build all archs.
export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a,x86" # x86 is required for E2E testing
if [[ "${{ inputs.run-e2e-tests }}" == 'true' ]]; then
export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a,x86" # x86 is required for E2E testing
else
export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a"
fi
TASKS="publishAllToMavenTempLocal build"
elif [[ "${{ inputs.release-type }}" == "nightly" ]]; then
# nightly: we set isSnapshot to true so artifacts are sent to the right repository on Maven Central.
@@ -57,7 +63,7 @@ runs:
uses: actions/cache/save@v4
with:
path: /github/home/.cache/ccache
key: v2-ccache-android-${{ github.job }}-${{ github.ref }}-${{ hashFiles('packages/react-native/ReactAndroid/**/*.cpp', 'packages/react-native/ReactAndroid/**/*.h', 'packages/react-native/ReactCommon/**/*.cpp', 'packages/react-native/ReactAndroid/**/CMakeLists.txt', 'packages/react-native/ReactCommon/**/CMakeLists.txt') }}
key: v1-ccache-android-${{ github.job }}-${{ github.ref }}
- name: Show ccache stats
shell: bash
run: ccache -s -v
@@ -71,17 +71,17 @@ runs:
mv build_"$SLICE" "$FINAL_PATH"
# check whether everything is there
if [[ -d "$FINAL_PATH/lib/hermesvm.framework" ]]; then
echo "Successfully built hermesvm.framework for $SLICE in $FLAVOR"
if [[ -d "$FINAL_PATH/API/hermes/hermes.framework" ]]; then
echo "Successfully built hermes.framework for $SLICE in $FLAVOR"
else
echo "Failed to built hermesvm.framework for $SLICE in $FLAVOR"
echo "Failed to built hermes.framework for $SLICE in $FLAVOR"
exit 1
fi
if [[ -d "$FINAL_PATH/lib/hermesvm.framework.dSYM" ]]; then
echo "Successfully built hermesvm.framework.dSYM for $SLICE in $FLAVOR"
if [[ -d "$FINAL_PATH/API/hermes/hermes.framework.dSYM" ]]; then
echo "Successfully built hermes.framework.dSYM for $SLICE in $FLAVOR"
else
echo "Failed to built hermesvm.framework.dSYM for $SLICE in $FLAVOR"
echo "Failed to built hermes.framework.dSYM for $SLICE in $FLAVOR"
echo "Please try again"
exit 1
fi
@@ -15,6 +15,8 @@ runs:
steps:
- name: Setup xcode
uses: ./.github/actions/setup-xcode
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Restore Hermes workspace
uses: ./.github/actions/restore-hermes-workspace
- name: Restore Cached Artifacts
@@ -43,8 +45,6 @@ runs:
echo "ARTIFACTS_EXIST=true" >> $GITHUB_ENV
echo "ARTIFACTS_EXIST=true" >> $GITHUB_OUTPUT
fi
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Yarn- Install Dependencies
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: ./.github/actions/yarn-install
@@ -186,7 +186,7 @@ runs:
cd ./packages/react-native/sdks/hermes || exit 1
DSYM_FILE_PATH=lib/hermesvm.framework.dSYM
DSYM_FILE_PATH=API/hermes/hermes.framework.dSYM
cp -r build_macosx/$DSYM_FILE_PATH "$WORKING_DIR/macosx/"
cp -r build_catalyst/$DSYM_FILE_PATH "$WORKING_DIR/catalyst/"
cp -r build_iphoneos/$DSYM_FILE_PATH "$WORKING_DIR/iphoneos/"
@@ -197,10 +197,10 @@ runs:
cp -r build_xrsimulator/$DSYM_FILE_PATH "$WORKING_DIR/xrsimulator/"
DEST_DIR="/tmp/hermes/dSYM/$FLAVOR"
tar -C "$WORKING_DIR" -czvf "hermesvm.framework.dSYM" .
tar -C "$WORKING_DIR" -czvf "hermes.framework.dSYM" .
mkdir -p "$DEST_DIR"
mv "hermesvm.framework.dSYM" "$DEST_DIR"
mv "hermes.framework.dSYM" "$DEST_DIR"
- name: Upload hermes dSYM artifacts
uses: actions/upload-artifact@v4.3.4
with:
@@ -14,23 +14,23 @@ runs:
uses: actions/download-artifact@v4
with:
name: hermes-workspace
path: 'C:\tmp\hermes'
path: 'D:\tmp\hermes'
- name: Set up workspace
shell: powershell
run: |
mkdir -p C:\tmp\hermes\osx-bin
mkdir -p D:\tmp\hermes\osx-bin
mkdir -p .\packages\react-native\sdks\hermes
cp -r -Force C:\tmp\hermes\hermes\* .\packages\react-native\sdks\hermes\.
cp -r -Force D:\tmp\hermes\hermes\* .\packages\react-native\sdks\hermes\.
cp -r -Force .\packages\react-native\sdks\hermes-engine\utils\* .\packages\react-native\sdks\hermes\.
- name: Windows cache
uses: actions/cache@v4
with:
key: v3-hermes-${{ github.job }}-windows-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
path: |
C:\tmp\hermes\win64-bin\
C:\tmp\hermes\hermes\icu\
C:\tmp\hermes\hermes\deps\
C:\tmp\hermes\hermes\build_release\
D:\tmp\hermes\win64-bin\
D:\tmp\hermes\hermes\icu\
D:\tmp\hermes\hermes\deps\
D:\tmp\hermes\hermes\build_release\
- name: setup-msbuild
uses: microsoft/setup-msbuild@v1.3.2
- name: Set up workspace
@@ -83,4 +83,4 @@ runs:
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-win64-bin
path: C:\tmp\hermes\win64-bin\
path: D:\tmp\hermes\win64-bin\
+4 -4
View File
@@ -99,8 +99,8 @@ runs:
mkdir -p ./packages/react-native/ReactAndroid/external-artifacts/artifacts/
cp ${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-Debug.tar.gz ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-ios-debug.tar.gz
cp ${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-Release.tar.gz ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-ios-release.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Debug/hermesvm.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-debug.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Release/hermesvm.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-release.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Debug/hermes.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-debug.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Release/hermes.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-release.tar.gz
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
@@ -116,12 +116,12 @@ runs:
- name: Print Artifacts Directory
shell: bash
run: ls -lR ./packages/react-native/ReactAndroid/external-artifacts/artifacts/
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Setup gradle
uses: ./.github/actions/setup-gradle
with:
cache-encryption-key: ${{ inputs.gradle-cache-encryption-key }}
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Build packages
@@ -14,8 +14,6 @@ inputs:
runs:
using: composite
steps:
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Yarn install
uses: ./.github/actions/yarn-install
- name: Configure Git
@@ -1,23 +0,0 @@
name: diff-js-api-breaking-changes
description: Check for breaking changes in the public React Native JS API
runs:
using: composite
steps:
- name: Fetch snapshot from PR head
shell: bash
env:
SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-breaking-changes
run: |
mkdir $SCRATCH_DIR
git fetch --depth=1 origin ${{ github.event.pull_request.head.sha }}
git show ${{ github.event.pull_request.head.sha }}:packages/react-native/ReactNativeApi.d.ts > $SCRATCH_DIR/ReactNativeApi-after.d.ts \
|| echo "" > $SCRATCH_DIR/ReactNativeApi.d.ts
- name: Run breaking change detection
shell: bash
env:
SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-breaking-changes
run: |
node ./scripts/js-api/diff-api-snapshot \
${{ github.workspace }}/packages/react-native/ReactNativeApi.d.ts \
$SCRATCH_DIR/ReactNativeApi-after.d.ts \
> $SCRATCH_DIR/output.json
-2
View File
@@ -35,8 +35,6 @@ runs:
with:
java-version: '17'
distribution: 'zulu'
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Start Metro in Debug
@@ -17,6 +17,9 @@ outputs:
runs:
using: composite
steps:
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Setup hermes version
shell: bash
id: hermes-version
@@ -64,8 +67,6 @@ runs:
echo "HERMES_CACHED=true" >> "$GITHUB_OUTPUT"
fi
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Yarn- Install Dependencies
if: ${{ steps.meaningful-cache.outputs.HERMES_CACHED != 'true' }}
uses: ./.github/actions/yarn-install
@@ -1,83 +0,0 @@
name: Run Fantom Tests
inputs:
release-type:
required: true
description: The type of release we are building. It could be nightly, release or dry-run
gradle-cache-encryption-key:
description: "The encryption key needed to store the Gradle Configuration cache"
runs:
using: composite
steps:
- name: Install dependencies
shell: bash
run: |
sudo apt update
sudo apt install -y git cmake openssl libssl-dev clang
- name: Setup git safe folders
shell: bash
run: git config --global --add safe.directory '*'
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Install node dependencies
uses: ./.github/actions/yarn-install
- name: Setup gradle
uses: ./.github/actions/setup-gradle
with:
cache-read-only: "false"
cache-encryption-key: ${{ inputs.gradle-cache-encryption-key }}
- name: Restore Fantom ccache
uses: actions/cache/restore@v4
with:
path: /github/home/.cache/ccache
key: v2-ccache-fantom-${{ github.job }}-${{ github.ref }}-${{ hashFiles(
'packages/react-native/ReactAndroid/**/*.cpp',
'packages/react-native/ReactAndroid/**/*.h',
'packages/react-native/ReactAndroid/**/CMakeLists.txt',
'packages/react-native/ReactCommon/**/*.cpp',
'packages/react-native/ReactCommon/**/*.h',
'packages/react-native/ReactCommon/**/CMakeLists.txt',
'private/react-native-fantom/tester/**/*.cpp',
'private/react-native-fantom/tester/**/*.h',
'private/react-native-fantom/tester/**/CMakeLists.txt'
) }}
restore-keys: |
v2-ccache-fantom-${{ github.job }}-${{ github.ref }}-
v2-ccache-fantom-${{ github.job }}-
v2-ccache-fantom-
- name: Show ccache stats
shell: bash
run: ccache -s -v
- name: Run Fantom Tests
shell: bash
run: yarn fantom
env:
CC: clang
CXX: clang++
- name: Save Fantom ccache
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }}
uses: actions/cache/save@v4
with:
path: /github/home/.cache/ccache
key: v2-ccache-fantom-${{ github.job }}-${{ github.ref }}-${{ hashFiles(
'packages/react-native/ReactAndroid/**/*.cpp',
'packages/react-native/ReactAndroid/**/*.h',
'packages/react-native/ReactAndroid/**/CMakeLists.txt',
'packages/react-native/ReactCommon/**/*.cpp',
'packages/react-native/ReactCommon/**/*.h',
'packages/react-native/ReactCommon/**/CMakeLists.txt',
'private/react-native-fantom/tester/**/*.cpp',
'private/react-native-fantom/tester/**/*.h',
'private/react-native-fantom/tester/**/CMakeLists.txt'
) }}
- name: Show ccache stats
shell: bash
run: ccache -s -v
- name: Upload test results
if: ${{ always() }}
uses: actions/upload-artifact@v4.3.4
with:
name: run-fantom-tests-results
compression-level: 1
path: |
private/react-native-fantom/build/reports
+1 -1
View File
@@ -4,7 +4,7 @@ inputs:
node-version:
description: 'The node.js version to use'
required: false
default: '22.14.0'
default: '22'
runs:
using: "composite"
steps:
@@ -0,0 +1,32 @@
name: setup-xcode-build-cache
description: Add caching to iOS jobs to speed up builds
inputs:
hermes-version:
description: The version of hermes
required: true
flavor:
description: The flavor that is going to be built
default: Debug
use-frameworks:
description: Whether we are bulding with DynamicFrameworks or StaticLibraries
default: StaticLibraries
ruby-version:
description: The ruby version we are going to use
default: 2.6.10
runs:
using: composite
steps:
- name: See commands.yml with_xcodebuild_cache
shell: bash
run: echo "See commands.yml with_xcodebuild_cache"
- name: Cache podfile lock
uses: actions/cache@v4
with:
path: packages/rn-tester/Podfile.lock
key: v13-podfilelock-${{ github.job }}-NewArch-${{ inputs.flavor }}-${{ inputs.use-frameworks }}-${{ inputs.ruby-version }}-${{ hashfiles('packages/rn-tester/Podfile') }}-${{ inputs.hermes-version }}
- name: Cache cocoapods
uses: actions/cache@v4
with:
path: packages/rn-tester/Pods
key: v15-cocoapods-${{ github.job }}-NewArch-${{ inputs.flavor }}-${{ inputs.use-frameworks }}-${{ inputs.ruby-version }}-${{ hashfiles('packages/rn-tester/Podfile.lock') }}-${{ hashfiles('packages/rn-tester/Podfile') }}-${{ inputs.hermes-version}}
+2 -11
View File
@@ -23,8 +23,6 @@ runs:
uses: ./.github/actions/setup-xcode
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Create Hermes folder
shell: bash
run: mkdir -p "$HERMES_WS_DIR"
@@ -36,6 +34,8 @@ runs:
- name: Print Downloaded hermes
shell: bash
run: ls -lR "$HERMES_WS_DIR"
- name: Run yarn
uses: ./.github/actions/yarn-install
- name: Setup ruby
uses: ruby/setup-ruby@v1
with:
@@ -48,14 +48,6 @@ runs:
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
uses: actions/download-artifact@v4
with:
name: ReactCore${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/ReactCore
- name: Print ReactCore folder
shell: bash
run: ls -lR /tmp/ReactCore
- name: Install iOS dependencies - Configuration ${{ inputs.flavor }};
shell: bash
run: |
@@ -81,7 +73,6 @@ runs:
TARBALL_FILENAME=$(node ../../packages/react-native/scripts/hermes/get-tarball-name.js --buildType "$BUILD_TYPE")
export HERMES_ENGINE_TARBALL_PATH="$HERMES_WS_DIR/hermes-runtime-darwin/$TARBALL_FILENAME"
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ inputs.flavor }}.xcframework.tar.gz"
yarn bootstrap ios "${args[@]}" | cat
+7 -9
View File
@@ -94,25 +94,23 @@ runs:
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
uses: actions/download-artifact@v4
- name: Setup xcode build cache
uses: ./.github/actions/setup-xcode-build-cache
with:
name: ReactCore${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/ReactCore
- name: Print ReactCore folder
shell: bash
run: ls -lR /tmp/ReactCore
hermes-version: ${{ inputs.hermes-version }}
use-frameworks: ${{ inputs.use-frameworks }}
flavor: ${{ inputs.flavor }}
ruby-version: ${{ inputs.ruby-version }}
- name: Install CocoaPods dependencies
shell: bash
run: |
export HERMES_ENGINE_TARBALL_PATH=$HERMES_ENGINE_TARBALL_PATH
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ inputs.flavor }}.xcframework.tar.gz"
if [[ ${{ inputs.use-frameworks }} == "DynamicFrameworks" ]]; then
export USE_FRAMEWORKS=dynamic
fi
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
cd packages/rn-tester
bundle install
@@ -0,0 +1,52 @@
name: test-library-on-nightly
description: Tests a library on a nightly
inputs:
library-npm-package:
description: The library npm package to add
required: true
platform:
description: whether we want to build for iOS or Android
required: true
runs:
using: composite
steps:
- name: Create new app
shell: bash
run: |
cd /tmp
npx @react-native-community/cli init RNApp --skip-install --version nightly
- name: Add library
shell: bash
run: |
cd /tmp/RNApp
yarn add ${{ inputs.library-npm-package }}
# iOS
- name: Setup xcode
if: ${{ inputs.platform == 'ios' }}
uses: ./.github/actions/setup-xcode
- name: Build iOS
shell: bash
if: ${{ inputs.platform == 'ios' }}
run: |
cd /tmp/RNApp/ios
bundle install
bundle exec pod install
xcodebuild build \
-workspace RNApp.xcworkspace \
-scheme RNApp \
-sdk iphonesimulator
# Android
- name: Setup Java for Android
if: ${{ inputs.platform == 'android' }}
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'zulu'
- name: Build Android
shell: bash
if: ${{ inputs.platform == 'android' }}
run: |
cd /tmp/RNApp/android
./gradlew assembleDebug
@@ -188,7 +188,6 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/
status: 201,
json: () =>
Promise.resolve({
id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
}),
@@ -209,11 +208,9 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/
body: fetchBody,
},
);
expect(response).toEqual({
id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
});
expect(response).toEqual(
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
);
});
it('creates a draft release for prerelease on GitHub', async () => {
@@ -241,7 +238,6 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/
status: 201,
json: () =>
Promise.resolve({
id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
}),
@@ -262,11 +258,9 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/
body: fetchBody,
},
);
expect(response).toEqual({
id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
});
expect(response).toEqual(
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
);
});
it('throws if the post failes', async () => {
@@ -0,0 +1,189 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
prepareFailurePayload,
sendMessageToDiscord,
} = require('../notifyDiscord');
describe('prepareFailurePayload', () => {
it('should handle undefined failures', () => {
const message = prepareFailurePayload(undefined);
expect(message).toEqual({
content:
'⚠️ **React Native Nightly Integration Failures** ⚠️\n\nNo failures to report.',
});
});
it('should handle empty failures array', () => {
const message = prepareFailurePayload([]);
expect(message).toEqual({
content:
'⚠️ **React Native Nightly Integration Failures** ⚠️\n\nNo failures to report.',
});
});
it('should format a single failure correctly', () => {
const failures = [
{
library: 'react-native-reanimated',
platform: 'iOS',
},
];
const message = prepareFailurePayload(failures);
expect(message).toEqual({
content:
'⚠️ **React Native Nightly Integration Failures** ⚠️\n\nThe integration of libraries with React Native nightly failed for the following libraries:\n\n❌ [iOS] react-native-reanimated',
});
});
it('should sort multiple failures by platform and library name', () => {
const failures = [
{
library: 'react-native-reanimated',
platform: 'iOS',
},
{
library: 'react-native-gesture-handler',
platform: 'Android',
},
{
library: 'react-native-screens',
platform: 'iOS',
},
{
library: 'react-native-svg',
platform: 'Android',
},
];
const message = prepareFailurePayload(failures);
// The failures should be sorted: first Android (alphabetically), then iOS
// Within each platform, libraries should be sorted alphabetically
expect(message).toEqual({
content:
'⚠️ **React Native Nightly Integration Failures** ⚠️\n\nThe integration of libraries with React Native nightly failed for the following libraries:\n\n❌ [Android] react-native-gesture-handler\n❌ [Android] react-native-svg\n❌ [iOS] react-native-reanimated\n❌ [iOS] react-native-screens',
});
});
it('should handle failures with missing properties', () => {
const failures = [
{
// Missing library
platform: 'iOS',
},
{
library: 'react-native-gesture-handler',
// Missing platform
},
{
// Both missing
},
];
const message = prepareFailurePayload(failures);
expect(message).toEqual({
content:
'⚠️ **React Native Nightly Integration Failures** ⚠️\n\nThe integration of libraries with React Native nightly failed for the following libraries:\n\n❌ [iOS] Unknown\n❌ [Unknown] react-native-gesture-handler\n❌ [Unknown] Unknown',
});
});
});
describe('sendMessageToDiscord', () => {
// Store the original fetch function
const originalFetch = global.fetch;
// Setup and teardown for each test
beforeEach(() => {
// Mock the global fetch function
global.fetch = jest.fn();
// Silence console logs during tests
jest.spyOn(console, 'log').mockImplementation(() => {});
jest.spyOn(console, 'error').mockImplementation(() => {});
});
afterEach(() => {
// Restore the original fetch function
global.fetch = originalFetch;
// Restore console functions
jest.restoreAllMocks();
});
it('should throw an error if webhook URL is missing', async () => {
await expect(sendMessageToDiscord(null, {})).rejects.toThrow(
'Discord webhook URL is missing',
);
});
it('should send a message successfully', async () => {
// Mock a successful response
global.fetch.mockResolvedValueOnce({
ok: true,
status: 200,
});
const webhook = 'https://discord.com/api/webhooks/123/abc';
const message = {content: 'Test message'};
await expect(sendMessageToDiscord(webhook, message)).resolves.not.toThrow();
// Verify fetch was called with the right arguments
expect(global.fetch).toHaveBeenCalledWith(webhook, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(message),
});
// Verify console.log was called
expect(console.log).toHaveBeenCalledWith(
'Successfully sent message to Discord',
);
});
it('should throw an error if the response is not ok', async () => {
// Mock a failed response
global.fetch.mockResolvedValueOnce({
ok: false,
status: 400,
text: jest.fn().mockResolvedValueOnce('Bad Request'),
});
const webhook = 'https://discord.com/api/webhooks/123/abc';
const message = {content: 'Test message'};
await expect(sendMessageToDiscord(webhook, message)).rejects.toThrow(
'HTTP status code: 400',
);
// Verify console.error was called
expect(console.error).toHaveBeenCalledWith(
'Failed to send message to Discord: 400 Bad Request',
);
});
it('should throw an error if fetch fails', async () => {
// Mock a network error
const networkError = new Error('Network error');
global.fetch.mockRejectedValueOnce(networkError);
const webhook = 'https://discord.com/api/webhooks/123/abc';
const message = {content: 'Test message'};
await expect(sendMessageToDiscord(webhook, message)).rejects.toThrow(
'Network error',
);
});
});
@@ -117,13 +117,13 @@ describe('#verifyPublishedTemplate', () => {
it('will timeout if npm does not update package version after a set number of retries', async () => {
const RETRIES = 2;
(await verifyPublishedTemplate('0.77.0', true, RETRIES),
await verifyPublishedTemplate('0.77.0', true, RETRIES),
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'@react-native-community/template',
'0.77.0',
'latest',
2,
));
);
});
});
});
@@ -38,7 +38,7 @@ describe('#verifyArtifactsAreOnMaven', () => {
expect(mockSleep).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1',
);
});
@@ -55,7 +55,7 @@ describe('#verifyArtifactsAreOnMaven', () => {
expect(mockSleep).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1',
);
});
@@ -67,7 +67,7 @@ describe('#verifyArtifactsAreOnMaven', () => {
expect(mockSleep).toHaveBeenCalledTimes(0);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1',
);
});
@@ -81,7 +81,7 @@ describe('#verifyArtifactsAreOnMaven', () => {
expect(mockSleep).toHaveBeenCalledTimes(90);
expect(mockExit).toHaveBeenCalledWith(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1',
);
});
});
@@ -83,13 +83,13 @@ describe('#verifyReleaseOnNPM', () => {
it('will timeout if npm does not update package version after a set number of retries', async () => {
const RETRIES = 2;
(await verifyReleaseOnNpm('0.77.0', true, RETRIES),
await verifyReleaseOnNpm('0.77.0', true, RETRIES),
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'react-native',
'0.77.0',
'latest',
2,
));
);
});
it('will timeout if npm does not update latest tag after a set number of retries', async () => {
@@ -0,0 +1,121 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
const fs = require('fs');
const path = require('path');
const {
prepareFailurePayload,
sendMessageToDiscord,
} = require('./notifyDiscord');
function readOutcomes() {
const baseDir = '/tmp';
let outcomes = [];
fs.readdirSync(baseDir).forEach(file => {
const fullPath = path.join(baseDir, file);
if (fullPath.endsWith('outcome') && fs.statSync(fullPath).isDirectory) {
fs.readdirSync(fullPath).forEach(subFile => {
const subFullPath = path.join(fullPath, subFile);
if (subFullPath.endsWith('outcome')) {
const [library, status] = String(fs.readFileSync(subFullPath, 'utf8'))
.trim()
.split(':');
const platform = subFile.includes('android') ? 'Android' : 'iOS';
console.log(
`[${platform}] ${library} completed with status ${status}`,
);
outcomes.push({
library: library.trim(),
platform,
status: status.trim(),
});
}
});
} else if (fullPath.endsWith('outcome')) {
const [library, status] = String(fs.readFileSync(fullPath, 'utf8'))
.trim()
.split(':');
const platform = file.includes('android') ? 'Android' : 'iOS';
console.log(`[${platform}] ${library} completed with status ${status}`);
outcomes.push({
library: library.trim(),
platform,
status: status.trim(),
});
}
});
return outcomes;
}
function printFailures(outcomes) {
console.log('Printing failures...');
let failedLibraries = [];
outcomes.forEach(entry => {
if (entry.status !== 'success') {
console.log(
`❌ [${entry.platform}] ${entry.library} failed with status ${entry.status}`,
);
failedLibraries.push({
library: entry.library,
platform: entry.platform,
});
}
});
return failedLibraries;
}
/**
* Sends a message to Discord with the list of failures.
* @param {string} webHook - The Discord webhook URL
* @param {Array<Object>} failures - List of failures to report
* @returns {Promise<void>} - A promise that resolves when the message is sent
*/
async function notifyDiscord(webHook, failures) {
if (!webHook) {
console.error('Discord webhook URL is missing');
return;
}
if (!failures || failures.length === 0) {
console.log('No failures to report to Discord');
return;
}
try {
// Use the prepareFailurePayload function to format the message
const message = prepareFailurePayload(failures);
// Use the sendMessageToDiscord function to send the message
await sendMessageToDiscord(webHook, message);
} catch (error) {
console.error('Error in notifyDiscord function:', error);
throw error;
}
}
async function collectResults(discordWebHook) {
const outcomes = readOutcomes();
const failures = printFailures(outcomes);
if (failures.length > 0) {
if (discordWebHook) {
console.log('Sending to discord');
await notifyDiscord(discordWebHook, failures);
} else {
console.log('Web hook not set');
}
process.exit(1);
}
console.log('✅ All tests passed!');
}
module.exports = {
collectResults,
notifyDiscord,
};
@@ -101,11 +101,7 @@ async function _createDraftReleaseOnGitHub(version, body, latest, token) {
}
const data = await response.json();
const {html_url, id} = data;
return {
html_url,
id,
};
return data.html_url;
}
function moveToChangelogBranch(version) {
@@ -128,8 +124,7 @@ async function createDraftRelease(version, latest, token) {
latest,
token,
);
log(`Created draft release: ${release.html_url}, ID ${release.id}`);
return release;
log(`Created draft release: ${release}`);
}
module.exports = {
@@ -25,31 +25,6 @@ function extractUsersFromScheduleAndDate(schedule, userMap, date) {
return [user1, user2];
}
/**
* You can invoke this script by doing:
* ```
* node .github/workflow-scripts/extractIssueOncalls.js $DATA
* ```
*
* the $DATA is stored in the github secrets as ONCALL_SCHEDULE variable.
* The format of the data is:
* ```
* {
* \"userMap\": {
* \"discord_handle1\": \"discord_id1\",
* \"discord_handle2\": \"discord_id2\",
* ...
* },
* \"schedule\": {
* \"2025-07-29\": [\"discord_handle1\", \"discord_handle2\"],
* \"2025-08-05\": [\"discord_handle3\", \"discord_handle4\"],
* ...
* }
* ```
*
* When uploading the secret, make sure that the JSON strings are escaped!
* The script will fail otherwise, because GitHub will remove the `"` characters.
*/
function main() {
const configuration = process.argv[2];
const {userMap, schedule} = JSON.parse(configuration);
+2 -2
View File
@@ -87,11 +87,11 @@ async function launchAppOnSimulator(appId, udid, isDebug) {
function startVideoRecording(jsengine, currentAttempt) {
console.log(
`Start video record using pid: video_record_${currentAttempt}.pid`,
`Start video record using pid: video_record_${jsengine}_${currentAttempt}.pid`,
);
const recordingArgs =
`simctl io booted recordVideo video_record_${currentAttempt}.mov`.split(
`simctl io booted recordVideo video_record_${jsengine}_${currentAttempt}.mov`.split(
' ',
);
const recordingProcess = childProcess.spawn('xcrun', recordingArgs, {
+90
View File
@@ -0,0 +1,90 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
/**
* Sends a message to Discord using the webhook URL.
* @param {string} webHook - The Discord webhook URL
* @param {Object} message - The message to send
* @returns {Promise<void>} - A promise that resolves when the message is sent
*/
async function sendMessageToDiscord(webHook, message) {
if (!webHook) {
throw new Error('Discord webhook URL is missing');
}
// Send the request using fetch
const response = await fetch(webHook, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(message),
});
// Handle the response
if (response.ok) {
console.log('Successfully sent message to Discord');
return;
} else {
const errorText = await response.text();
console.error(
`Failed to send message to Discord: ${response.status} ${errorText}`,
);
throw new Error(`HTTP status code: ${response.status}`);
}
}
/**
* Prepares a formatted Discord message payload from a list of failures.
* @param {Array<Object>} failures - List of failures to format
* @returns {Object} - The formatted Discord message payload
*/
function prepareFailurePayload(failures) {
if (!failures || failures.length === 0) {
return {
content:
'⚠️ **React Native Nightly Integration Failures** ⚠️\n\nNo failures to report.',
};
}
// Sort failures by platform and then by library name
const sortedFailures = [...failures].sort((a, b) => {
// First sort by platform
const platformA = a.platform || 'Unknown';
const platformB = b.platform || 'Unknown';
if (platformA !== platformB) {
return platformA.localeCompare(platformB);
}
// Then sort by library name
const libraryA = a.library || 'Unknown';
const libraryB = b.library || 'Unknown';
return libraryA.localeCompare(libraryB);
});
// Format the failures into a message
const formattedFailures = sortedFailures
.map(failure => {
const library = failure.library || 'Unknown';
const platform = failure.platform || 'Unknown';
return `❌ [${platform}] ${library}`;
})
.join('\n');
return {
content: `⚠️ **React Native Nightly Integration Failures** ⚠️\n\nThe integration of libraries with React Native nightly failed for the following libraries:\n\n${formattedFailures}`,
};
}
// Export the functions using CommonJS syntax
module.exports = {
prepareFailurePayload,
sendMessageToDiscord,
};
@@ -13,14 +13,13 @@ const SLEEP_S = 60; // 1 minute
const MAX_RETRIES = 90; // 90 attempts. Waiting between attempt: 1 min. Total time: 90 min.
const ARTIFACT_URL =
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/';
const ARTIFACT_NAME = 'react-native-artifacts-';
async function verifyArtifactsAreOnMaven(version, retries = MAX_RETRIES) {
if (version.startsWith('v')) {
version = version.substring(1);
}
const artifactUrl = `${ARTIFACT_URL}${version}/${ARTIFACT_NAME}${version}.pom`;
const artifactUrl = `${ARTIFACT_URL}${version}`;
for (let currentAttempt = 1; currentAttempt <= retries; currentAttempt++) {
const response = await fetch(artifactUrl);
-4
View File
@@ -18,10 +18,6 @@ jobs:
run: |
git config --local user.email "bot@reactnative.dev"
git config --local user.name "React Native Bot"
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
xcode-version: '16.2.0'
- name: Extract branch name
run: |
TAG="${{ github.ref_name }}";
+34
View File
@@ -0,0 +1,34 @@
# This jobs runs every day 2 hours after the nightly job and its purpose is to report
# a failure in case the nightly failed to be published. We are going to hook this to an internal automation.
name: Check Nightlies
on:
workflow_dispatch:
# nightly build @ 4:15 AM UTC
schedule:
- cron: '15 4 * * *'
jobs:
check-nightly:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check nightly
run: |
TODAY=$(date "+%Y%m%d")
echo "Checking nightly for $TODAY"
NIGHTLY="$(npm view react-native | grep $TODAY)"
if [[ -z $NIGHTLY ]]; then
echo 'Nightly job failed.'
exit 1
else
echo 'Nightly Worked, All Good!'
fi
test-libraries:
uses: ./.github/workflows/test-libraries-on-nightlies.yml
needs: check-nightly
secrets:
discord_webhook_url: ${{ secrets.NIGHTLY_DISCORD_WEBHOOK }}
+1 -16
View File
@@ -21,24 +21,9 @@ jobs:
git config --local user.name "React Native Bot"
- name: Create draft release
uses: actions/github-script@v6
id: create-draft-release
with:
script: |
const {createDraftRelease} = require('./.github/workflow-scripts/createDraftRelease.js');
const version = '${{ github.ref_name }}';
const {isLatest} = require('./.github/workflow-scripts/publishTemplate.js');
return (await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}')).id;
result-encoding: string
- name: Upload release assets for DotSlash
uses: actions/github-script@v6
env:
RELEASE_ID: ${{ steps.create-draft-release.outputs.result }}
with:
script: |
const {uploadReleaseAssetsForDotSlashFiles} = require('./scripts/releases/upload-release-assets-for-dotslash.js');
const version = '${{ github.ref_name }}';
await uploadReleaseAssetsForDotSlashFiles({
version,
token: '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}',
releaseId: process.env.RELEASE_ID,
});
await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}');
-1
View File
@@ -19,7 +19,6 @@ on:
jobs:
create_release:
if: github.repository == 'facebook/react-native'
runs-on: ubuntu-latest
steps:
- name: Checkout
-2
View File
@@ -22,8 +22,6 @@ jobs:
uses: ./.github/actions/setup-node
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Run diff-js-api-breaking-changes
uses: ./.github/actions/diff-js-api-breaking-changes
- name: Danger
run: yarn danger ci --use-github-checks --failOnErrors
working-directory: private/react-native-bots
+4
View File
@@ -27,6 +27,10 @@ jobs:
ONCALL2=$(echo $ONCALLS | cut -d ' ' -f 2)
echo "oncall1=$ONCALL1" >> $GITHUB_ENV
echo "oncall2=$ONCALL2" >> $GITHUB_ENV
- name: Print oncalls
run: |
echo "oncall1: ${{ env.oncall1 }}"
echo "oncall2: ${{ env.oncall2 }}"
- name: Monitor New Issues
uses: react-native-community/repo-monitor@v1.0.1
with:
+6 -9
View File
@@ -23,7 +23,6 @@ jobs:
prepare_hermes_workspace:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
@@ -51,8 +50,8 @@ jobs:
- name: Build HermesC Apple
uses: ./.github/actions/build-hermesc-apple
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
hermes-version: ${{ needs.prepare_hermes_workspace.output.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.output.react-native-version }}
build_apple_slices_hermes:
runs-on: macos-14
@@ -76,7 +75,7 @@ jobs:
uses: ./.github/actions/build-apple-slices-hermes
with:
flavor: ${{ matrix.flavor }}
slice: ${{ matrix.slice }}
slice: ${{ matrix.slice}}
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
@@ -102,7 +101,6 @@ jobs:
flavor: ${{ matrix.flavor }}
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
secrets: inherit
@@ -130,9 +128,9 @@ jobs:
runs-on: windows-2025
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: 'C:\tmp\hermes'
HERMES_TARBALL_ARTIFACTS_DIR: 'C:\tmp\hermes\hermes-runtime-darwin'
HERMES_OSXBIN_ARTIFACTS_DIR: 'C:\tmp\hermes\osx-bin'
HERMES_WS_DIR: 'D:\tmp\hermes'
HERMES_TARBALL_ARTIFACTS_DIR: 'D:\tmp\hermes\hermes-runtime-darwin'
HERMES_OSXBIN_ARTIFACTS_DIR: 'D:\tmp\hermes\osx-bin'
ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
CMAKE_DIR: 'C:\Program Files\CMake\bin'
@@ -147,7 +145,6 @@ jobs:
build_android:
runs-on: 8-core-ubuntu
if: github.repository == 'facebook/react-native'
needs: [set_release_type]
container:
image: reactnativecommunity/react-native-android:latest
+5 -5
View File
@@ -23,7 +23,7 @@ jobs:
id: restore-ios-slice
uses: actions/cache/restore@v4
with:
key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }}
path: packages/react-native/
- name: Setup node.js
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
@@ -83,7 +83,7 @@ jobs:
# Move the XCFramework in the destination directory
mv /tmp/third-party/packages/react-native/third-party/ReactNativeDependencies.xcframework packages/react-native/third-party/ReactNativeDependencies.xcframework
VERSION=$(jq -r '.version' packages/react-native/package.json)
VERSION=$(jq -r '.version' package.json)
echo "$VERSION-${{matrix.flavor}}" > "packages/react-native/third-party/version.txt"
cat "packages/react-native/third-party/version.txt"
# Check destination directory
@@ -117,7 +117,7 @@ jobs:
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
with:
key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }}
path: |
packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products
packages/react-native/.build/headers
@@ -140,7 +140,7 @@ jobs:
uses: actions/cache/restore@v4
with:
path: packages/react-native/.build/output/xcframeworks
key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }}
- name: Setup node.js
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-node
@@ -209,4 +209,4 @@ jobs:
path: |
packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.xcframework.tar.gz
packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.framework.dSYM.tar.gz
key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }}
@@ -179,9 +179,8 @@ jobs:
- name: Compress and Rename dSYM
if: steps.restore-xcframework.outputs.cache-hit != 'true'
run: |
cd packages/react-native/third-party/Symbols/
tar -cz -f ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz .
mv ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz ./ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
tar -cz -f packages/react-native/third-party/Symbols/ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz \
packages/react-native/third-party/Symbols/ReactNativeDependencies.framework.dSYM
- name: Upload XCFramework Artifact
uses: actions/upload-artifact@v4
with:
@@ -9,7 +9,6 @@ on:
jobs:
publish_bumped_packages:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
steps:
+3 -5
View File
@@ -21,7 +21,6 @@ jobs:
prepare_hermes_workspace:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
@@ -99,7 +98,6 @@ jobs:
flavor: ${{ matrix.flavor }}
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
secrets: inherit
@@ -127,9 +125,9 @@ jobs:
runs-on: windows-2025
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: 'C:\tmp\hermes'
HERMES_TARBALL_ARTIFACTS_DIR: 'C:\tmp\hermes\hermes-runtime-darwin'
HERMES_OSXBIN_ARTIFACTS_DIR: 'C:\tmp\hermes\osx-bin'
HERMES_WS_DIR: 'D:\tmp\hermes'
HERMES_TARBALL_ARTIFACTS_DIR: 'D:\tmp\hermes\hermes-runtime-darwin'
HERMES_OSXBIN_ARTIFACTS_DIR: 'D:\tmp\hermes\osx-bin'
ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
CMAKE_DIR: 'C:\Program Files\CMake\bin'
-1
View File
@@ -9,7 +9,6 @@ on:
jobs:
rerun:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- name: rerun ${{ inputs.run_id }}
env:
+41 -52
View File
@@ -2,6 +2,11 @@ name: Test All
on:
workflow_dispatch:
inputs:
run-e2e-tests:
description: Whether to run E2E tests or not
type: boolean
default: false
pull_request:
push:
branches:
@@ -11,7 +16,6 @@ on:
jobs:
set_release_type:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
outputs:
RELEASE_TYPE: ${{ steps.set_release_type.outputs.RELEASE_TYPE }}
env:
@@ -35,7 +39,6 @@ jobs:
prepare_hermes_workspace:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
@@ -114,7 +117,6 @@ jobs:
flavor: ${{ matrix.flavor }}
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
secrets: inherit
@@ -126,7 +128,7 @@ jobs:
test_ios_rntester_ruby_3_2_0:
runs-on: macos-14
needs:
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core]
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
@@ -139,12 +141,31 @@ jobs:
ruby-version: "3.2.0"
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
flavor: Debug
test_ios_rntester_dynamic_frameworks:
runs-on: macos-14
needs:
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
continue-on-error: true
strategy:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run it
uses: ./.github/actions/test-ios-rntester
with:
use-frameworks: DynamicFrameworks
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
test_ios_rntester:
runs-on: macos-14-large
needs:
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core]
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
@@ -153,19 +174,20 @@ jobs:
fail-fast: false
matrix:
flavor: [Debug, Release]
frameworks: [StaticLibraries, DynamicFrameworks]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run it
uses: ./.github/actions/test-ios-rntester
with:
use-frameworks: ${{ matrix.frameworks }}
run-unit-tests: "false"
use-frameworks: StaticLibraries
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
flavor: ${{ matrix.flavor }}
test_e2e_ios_rntester:
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
runs-on: macos-14-large
needs:
[test_ios_rntester]
@@ -199,6 +221,7 @@ jobs:
flavor: ${{ matrix.flavor }}
test_e2e_ios_templateapp:
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
runs-on: macos-14-large
needs: [build_npm_package, prebuild_apple_dependencies]
env:
@@ -241,19 +264,6 @@ jobs:
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
uses: actions/download-artifact@v4
with:
name: ReactCore${{ matrix.flavor }}.xcframework.tar.gz
path: /tmp/ReactCore
- name: Print ReactCore folder
shell: bash
run: ls -lR /tmp/ReactCore
- name: Configure git
shell: bash
run: |
git config --global user.email "react-native-bot@meta.com"
git config --global user.name "React Native Bot"
- name: Prepare artifacts
run: |
REACT_NATIVE_PKG=$(find /tmp/react-native-tmp -type f -name "*.tgz")
@@ -276,8 +286,6 @@ jobs:
NEW_ARCH_ENABLED=1
export RCT_USE_LOCAL_RN_DEP=/tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
# Disable prebuilds for now, as they are causing issues with E2E tests for 0.82-stable branch
# export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ matrix.flavor }}.xcframework.tar.gz"
HERMES_ENGINE_TARBALL_PATH=$HERMES_PATH RCT_NEW_ARCH_ENABLED=$NEW_ARCH_ENABLED bundle exec pod install
xcodebuild \
@@ -297,6 +305,7 @@ jobs:
working-directory: /tmp/RNTestProject
test_e2e_android_templateapp:
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
runs-on: 4-core-ubuntu
needs: build_npm_package
strategy:
@@ -379,33 +388,13 @@ jobs:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
run_fantom_tests:
runs-on: 8-core-ubuntu
needs: [set_release_type]
container:
# Version is pinned to v18.0 to unblock `run_fantom_tests` - see https://github.com/react-native-community/docker-android/pull/242#issuecomment-3280029122
image: reactnativecommunity/react-native-android:v18.0
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test Fantom
uses: ./.github/actions/run-fantom-tests
with:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
build_hermesc_windows:
runs-on: windows-2025
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: 'C:\tmp\hermes'
HERMES_TARBALL_ARTIFACTS_DIR: 'C:\tmp\hermes\hermes-runtime-darwin'
HERMES_OSXBIN_ARTIFACTS_DIR: 'C:\tmp\hermes\osx-bin'
HERMES_WS_DIR: 'D:\tmp\hermes'
HERMES_TARBALL_ARTIFACTS_DIR: 'D:\tmp\hermes\hermes-runtime-darwin'
HERMES_OSXBIN_ARTIFACTS_DIR: 'D:\tmp\hermes\osx-bin'
ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
CMAKE_DIR: 'C:\Program Files\CMake\bin'
@@ -435,9 +424,11 @@ jobs:
uses: ./.github/actions/build-android
with:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
run-e2e-tests: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
test_e2e_android_rntester:
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
runs-on: 4-core-ubuntu
needs: [build_android]
strategy:
@@ -557,7 +548,7 @@ jobs:
test_ios_helloworld_with_ruby_3_2_0:
runs-on: macos-14
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
env:
PROJECT_NAME: iOSTemplateProject
HERMES_WS_DIR: /tmp/hermes
@@ -574,7 +565,7 @@ jobs:
test_ios_helloworld:
runs-on: macos-14
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
strategy:
matrix:
flavor: [Debug, Release]
@@ -599,11 +590,10 @@ jobs:
test_js:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
strategy:
fail-fast: false
matrix:
node-version: ["24.4.1", "22", "20.19.4"]
node-version: ["24", "22"]
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -614,7 +604,6 @@ jobs:
lint:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
@@ -637,7 +626,7 @@ jobs:
rerun-failed-jobs:
runs-on: ubuntu-latest
needs: [test_e2e_ios_rntester, test_e2e_android_rntester, test_e2e_ios_templateapp, test_e2e_android_templateapp]
if: ${{ github.ref == 'refs/heads/main' && always() }}
if: always()
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -0,0 +1,100 @@
name: Test Libraries on Nightlies
on:
workflow_call:
secrets:
discord_webhook_url:
required: true
# We use the matrix.library entry to specify the dependency we want to use
# The key is used directly as the <pkg> in the `yarn add <pkg>` command.
jobs:
runner-setup:
runs-on: ubuntu-latest
outputs:
runners: '{"ios":"macos-14-large", "android": "ubuntu-latest"}'
steps:
- run: echo no-op
test-library-on-nightly:
name: "[${{ matrix.platform }}] ${{ matrix.library }}"
needs: runner-setup
runs-on: ${{ fromJSON(needs.runner-setup.outputs.runners)[matrix.platform] }}
continue-on-error: true
strategy:
matrix:
library: [
"react-native-async-storage",
"react-native-blob-util",
"@react-native-clipboard/clipboard",
"@react-native-community/datetimepicker",
"react-native-gesture-handler",
"react-native-image-picker",
"react-native-linear-gradient",
"@react-native-masked-view/masked-view",
# "react-native-maps", React Native Maps with the New Arch support has a complex cocoapods setup for iOS. It needs a dedicated workflow.
"@react-native-community/netinfo",
"react-native-reanimated@nightly react-native-worklets@nightly", #reanimated requires worklet to be explicitly installed as a separate package
"react-native-svg",
"react-native-video",
"react-native-webview",
"react-native-mmkv",
"react-native-screens",
"react-native-pager-view",
"@react-native-community/slider",
# additional OSS libs used internally
"scandit-react-native-datacapture-barcode scandit-react-native-datacapture-core",
"react-native-contacts",
"react-native-device-info",
"react-native-email-link",
"@dr.pogodin/react-native-fs",
"react-native-permissions",
"react-native-vector-icons",
"react-native-masked-view",
"@react-native-community/image-editor",
]
platform: [ios, android]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: ./.github/actions/setup-node
- name: Test ${{ matrix.library }}
id: run-test
uses: ./.github/actions/test-library-on-nightly
with:
library-npm-package: ${{ matrix.library }}
platform: ${{ matrix.platform}}
- name: Save outcome
id: save-outcome
if: always()
run: |
LIB_FOLDER=$(echo "${{matrix.library}}" | tr ' ' '_' | tr '/' '_')
echo "${{matrix.library}}: ${{steps.run-test.outcome}}" > "/tmp/$LIB_FOLDER-${{ matrix.platform }}-outcome"
echo "lib_folder=$LIB_FOLDER" >> $GITHUB_OUTPUT
- name: Upload Artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ steps.save-outcome.outputs.lib_folder }}-${{ matrix.platform }}-outcome
path: /tmp/${{ steps.save-outcome.outputs.lib_folder }}-${{ matrix.platform }}-outcome
collect-results:
runs-on: ubuntu-latest
needs: [test-library-on-nightly]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Restore outcomes
uses: actions/download-artifact@v4
with:
pattern: '*-outcome'
path: /tmp
- name: Collect failures
uses: actions/github-script@v6
with:
script: |
const {collectResults} = require('./.github/workflow-scripts/collectNightlyOutcomes.js');
await collectResults('${{secrets.discord_webhook_url}}');
@@ -1,49 +0,0 @@
name: Validate DotSlash Artifacts
on:
workflow_dispatch:
release:
types: [published]
push:
branches:
- main
paths:
- packages/debugger-shell/bin/react-native-devtools
- "scripts/releases/**"
- package.json
- yarn.lock
pull_request:
branches:
- main
paths:
- packages/debugger-shell/bin/react-native-devtools
- "scripts/releases/**"
- package.json
- yarn.lock
# Same time as the nightly build: 2:15 AM UTC
schedule:
- cron: "15 2 * * *"
jobs:
validate-dotslash-artifacts:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Configure Git
shell: bash
run: |
git config --local user.email "bot@reactnative.dev"
git config --local user.name "React Native Bot"
- name: Validate DotSlash artifacts
uses: actions/github-script@v6
with:
script: |
const {validateDotSlashArtifacts} = require('./scripts/releases/validate-dotslash-artifacts.js');
await validateDotSlashArtifacts();
+1 -4
View File
@@ -43,6 +43,7 @@ project.xcworkspace
/private/helloworld/android/app/build/
/private/helloworld/android/build/
/packages/react-native-popup-menu-android/android/build/
/packages/react-native-test-library/android/build/
# Buck
.buckd
@@ -170,11 +171,7 @@ fix_*.patch
# Jest Integration
/private/react-native-fantom/build/
/private/react-native-fantom/.out/
/private/react-native-fantom/tester/build/
# [Experimental] Generated TS type definitions
/packages/**/types_generated/
/packages/debugger-shell/build/
/packages/*/dist/
+36
View File
@@ -0,0 +1,36 @@
{
"arrowParens": "avoid",
"bracketSameLine": true,
"bracketSpacing": false,
"requirePragma": true,
"singleQuote": true,
"trailingComma": "all",
"endOfLine": "lf",
"overrides": [
{
"files": ["*.code-workspace"],
"options": {
"parser": "json"
}
},
{
"files": [
"*.js",
"*.js.flow"
],
"options": {
"parser": "hermes"
}
},
{
"files": [
"**/__docs__/*.md"
],
"options": {
"parser": "markdown",
"proseWrap": "always",
"requirePragma": false
}
}
]
}
-46
View File
@@ -1,46 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
let plugins = ['prettier-plugin-hermes-parser'];
try {
plugins = require('./.prettier-plugins.fb.js');
} catch {}
module.exports = {
arrowParens: 'avoid',
bracketSameLine: true,
bracketSpacing: false,
requirePragma: true,
singleQuote: true,
trailingComma: 'all',
endOfLine: 'lf',
plugins,
overrides: [
{
files: ['*.code-workspace'],
options: {
parser: 'json',
},
},
{
files: ['*.js', '*.js.flow'],
options: {
parser: 'hermes',
},
},
{
files: ['**/__docs__/*.md'],
options: {
parser: 'markdown',
proseWrap: 'always',
requirePragma: false,
},
},
],
};
@@ -1,33 +1,5 @@
# Changelog (pre 0.80)
## v0.79.6
### Added
#### Android specific
- **RNGP** Add support for `exclusiveEnterpriseRepository` ([df5ac988ce](https://github.com/facebook/react-native/commit/df5ac988cec936c430d41b0fcc15181dc06e46a1) by [@cortinico](https://github.com/cortinico))
#### iOS specific
- **Cocoapods:** Add the ENTERPRISE_REPOSITORY env var to let user consume artifacts from their personal maven mirror ([a74d930c93](https://github.com/facebook/react-native/commit/a74d930c93ffae8c02142e8cc016a4c390a5f784) by [@cipolleschi](https://github.com/cipolleschi))
### Fixed
- **Codegen:** Add missing Babel dependencies ([bf2c3af93b](https://github.com/facebook/react-native/commit/bf2c3af93b146943cb35866fa9badcd188e63f5b) by [@tido64](https://github.com/tido64))
#### Android specific
- **Legacy Arch:** Fix Legacy arch crashing or freezing upon reload ([db600b2e9e](https://github.com/facebook/react-native/commit/db600b2e9e87863cad6dd5ce262dc1f793bcaeb0) by [@robhogan](https://github.com/robhogan))
- **Modal:** Fix Modal first frame being rendered on top-left corner ([5a315f8d6b](https://github.com/facebook/react-native/commit/5a315f8d6b0ea54442c7ef94b7346b0c73fd0b4c) by [@cortinico](https://github.com/cortinico))
- **TurboModule:** Fix emitting event from turbo module crashes on 32bit android ([43bc43e5e8](https://github.com/facebook/react-native/commit/43bc43e5e85519d2924c4fc80765e66d0c48b1a9) by [@vladimirivanoviliev](https://github.com/vladimirivanoviliev))
## v0.79.5
### Fixed
- **Flow:** Publish top-level Flow types for `react-native` ([fbbd20dd63](https://github.com/facebook/react-native/commit/fbbd20dd632acd72d2abe861dd4a0e6e98437cf2) by [@buschco](https://github.com/buschco))
## v0.79.4
### Fixed
@@ -341,31 +313,6 @@ ChuiHW))
- **JSC:** Clean up RCTBridgeDelegate to remove shouldBridgeUseCustomJSC method ([c8f1506f13](https://github.com/facebook/react-native/commit/c8f1506f13310ffafe370273805684e696d72d50) by [@zhongwuzw](https://github.com/zhongwuzw))
- **Layout:** Remove no longer needed UISceneDelegate ([a033cf9d5e](https://github.com/facebook/react-native/commit/a033cf9d5e8ffbda8b6f86cf3ce152b4ccb73187) by [@okwasniewski](https://github.com/okwasniewski))
## v0.78.3
### Added
#### Android specific
- **Gradle:** RNGP - Add support for `exclusiveEnterpriseRepository` to specify an internal Maven mirror. ([6cb8dc37c7](https://github.com/facebook/react-native/commit/6cb8dc37c74995cba3f9f0a845919f305de53c3d) by [@cortinico](https://github.com/cortinico))
### Fixed
- **DevTools**: Temporarily disable eager evaluation and live expressions in the console tab ([07717b5275](https://github.com/facebook/react-native/commit/07717b5275d80cde7b2b4edbe032ab629127fbf0) by [@huntie](https://github.com/huntie))
- **InteropLayer:** Fixed adding child views to a native view using the interop layer ([d53a60dd23](https://github.com/facebook/react-native/commit/d53a60dd23c5df8afca058a867c50df8b61f62e2) by [@chrfalch](https://github.com/chrfalch))
- **Runtime:** Align timer IDs and timer function argument error handling with web standards. ([480a4642e5](https://github.com/facebook/react-native/commit/480a4642e5a644becf1c477d3d239f9b57efff3a) by [@kitten](https://github.com/kitten))
#### Android specific
- **StyleSheet:** Wrong `borderBottomEndRadius` on RTL ([68d6ada448](https://github.com/facebook/react-native/commit/68d6ada44893701b6006a6b1753131c7e880a30a) by [@riteshshukla04](https://github.com/riteshshukla04))
#### iOS specific
- **Codegen:** Skip codegen for selectively disabled libraries in react-native.config.js ([be8595b18a](https://github.com/facebook/react-native/commit/be8595b18a46635bf679d8e7473f2960c33530fa) by [@ismarbesic](https://github.com/ismarbesic))
- **Layout:** Layout direction changes are now honored on bundle reload ([36f29beac4](https://github.com/facebook/react-native/commit/36f29beac47259768612bf56e5d9acfa4b94ab1a) by [@chrsmys](https://github.com/chrsmys))
- **Runtime:** Re-enable enableFixForViewCommandRace feature flag ([ae59702f8e](https://github.com/facebook/react-native/commit/ae59702f8ee89e7bddec971e0a041744cb91e65c) by [@okwasniewski](https://github.com/okwasniewski))
- **Switch:** Fixed switches correctly reverting to controlled state ([aa8c072870](https://github.com/facebook/react-native/commit/aa8c072870f6f9740e567a0f455c0e500ff1400c) by [@javache](https://github.com/javache))
## v0.78.2
### Changed
@@ -544,37 +491,6 @@ ChuiHW))
- **Style:** Fixed `centerContent` losing taps and causing jitter ([fe7e97a2fd](https://github.com/facebook/react-native/commit/fe7e97a2fd272db0d9d9aa7d0561337a7c8e2c30) by [@gaearon](https://github.com/gaearon))
- **Xcode:** Properly escape paths in Xcode build script used when bundling an app. ([2fee13094b](https://github.com/facebook/react-native/commit/2fee13094b3d384c071978776fd8b7cff0b6530f) by [@kraenhansen](https://github.com/kraenhansen))
# Changelog
## v0.77.3
### Added
#### Android specific
- **Gradle**: RNGP - Add support for `exclusiveEnterpriseRepository` to specify an internal Maven mirror. ([6cb8dc37c7](https://github.com/facebook/react-native/commit/6cb8dc37c74995cba3f9f0a845919f305de53c3d) by [@cortinico](https://github.com/cortinico))
### Changed
- **Metro**: Bump Metro minimum version from `^0.81.3` to `^0.81.5`. ([dfa81638dd](https://github.com/facebook/react-native/commit/dfa81638dd17e46f70f10b25c4f4fd9f370a4b0e) by [@robhogan](https://github.com/robhogan))
### Fixed
- **Timers**: Align timer IDs and timer function argument error handling with web standards. ([480a4642e5](https://github.com/facebook/react-native/commit/480a4642e5a644becf1c477d3d239f9b57efff3a) by [@kitten](https://github.com/kitten))
#### Android specific
- **Modal**: Fix Modal first frame being rendered on top-left corner. ([b950fa2afb](https://github.com/facebook/react-native/commit/b950fa2afb20e2213ff6c733cb1c2465b90406ef) by [@cortinico](https://github.com/cortinico))
- **layout**: Fix wrong `borderBottomEndRadius` on RTL. ([68d6ada448](https://github.com/facebook/react-native/commit/68d6ada44893701b6006a6b1753131c7e880a30a) by [@riteshshukla04](https://github.com/riteshshukla04))
- **Modal**: Fix `FLAG_SECURE` not respected in Modal dialog. ([7e029b0dcf](https://github.com/facebook/react-native/commit/7e029b0dcf6d1a6455a8a6343457b70e353d0ff6) by [@mateoguzmana](https://github.com/mateoguzmana))
- **lifecylcle**: Legacy arch: fix #50274, Fast Refresh sometimes breaks after full refresh. ([c43952ac22](https://github.com/facebook/react-native/commit/c43952ac22b2356be3130c906329f61e246082cb) by [@robhogan](https://github.com/robhogan))
#### iOS specific
- **Interop Layer**: Fixed adding child views to a native view using the interop layer. ([d53a60dd23](https://github.com/facebook/react-native/commit/d53a60dd23c5df8afca058a867c50df8b61f62e2) by [@chrfalch](https://github.com/chrfalch))
- **Debugger**: Restore "Paused in debugger" overlay icon. ([f30c46efbd](https://github.com/facebook/react-native/commit/f30c46efbd964d367f678181589865a3faa931cd) by [@robhogan](https://github.com/robhogan))
- **layout**: Layout direction changes are now honored on bundle reload. ([36f29beac4](https://github.com/facebook/react-native/commit/36f29beac47259768612bf56e5d9acfa4b94ab1a) by [@chrsmys](https://github.com/chrsmys))
- **file reads**: Fix crash caused by `[RCTFileRequestHanlder invalidate]`. ([789ed7d5ad](https://github.com/facebook/react-native/commit/789ed7d5ad75ad4c20ecd1eb19d1fc18275fc500) by [@zhouzh1](https://github.com/zhouzh1))
## v0.77.2
### Added
-1307
View File
File diff suppressed because it is too large Load Diff
+2 -5
View File
@@ -17,13 +17,10 @@
<img src="https://img.shields.io/npm/v/react-native?color=brightgreen&label=npm%20package" alt="Current npm package version." />
</a>
<a href="https://reactnative.dev/docs/contributing">
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs are welcome!" />
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs welcome!" />
</a>
<a href="https://twitter.com/intent/follow?screen_name=reactnative">
<img src="https://img.shields.io/twitter/follow/reactnative.svg?label=Follow%20@reactnative" alt="Follow @reactnative on X" />
</a>
<a href="https://bsky.app/profile/reactnative.dev">
<img src="https://img.shields.io/badge/Bluesky-0285FF?logo=bluesky&logoColor=fff" alt="Follow @reactnative.dev on Bluesky" />
<img src="https://img.shields.io/twitter/follow/reactnative.svg?label=Follow%20@reactnative" alt="Follow @reactnative" />
</a>
</p>
+10 -62
View File
@@ -13,7 +13,6 @@ plugins {
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.binary.compatibility.validator) apply true
alias(libs.plugins.android.test) apply false
alias(libs.plugins.ktfmt) apply true
}
val reactAndroidProperties = java.util.Properties()
@@ -26,12 +25,10 @@ fun getListReactAndroidProperty(name: String) = reactAndroidProperties.getProper
apiValidation {
ignoredPackages.addAll(
getListReactAndroidProperty("binaryCompatibilityValidator.ignoredPackages")
)
getListReactAndroidProperty("binaryCompatibilityValidator.ignoredPackages"))
ignoredClasses.addAll(getListReactAndroidProperty("binaryCompatibilityValidator.ignoredClasses"))
nonPublicMarkers.addAll(
getListReactAndroidProperty("binaryCompatibilityValidator.nonPublicMarkers")
)
getListReactAndroidProperty("binaryCompatibilityValidator.nonPublicMarkers"))
validationDisabled =
reactAndroidProperties
.getProperty("binaryCompatibilityValidator.validationDisabled")
@@ -39,9 +36,8 @@ apiValidation {
}
version =
if (
project.hasProperty("isSnapshot") && (project.property("isSnapshot") as? String).toBoolean()
) {
if (project.hasProperty("isSnapshot") &&
(project.property("isSnapshot") as? String).toBoolean()) {
"${reactAndroidProperties.getProperty("VERSION_NAME")}-SNAPSHOT"
} else {
reactAndroidProperties.getProperty("VERSION_NAME")
@@ -69,10 +65,8 @@ tasks.register("clean", Delete::class.java) {
description = "Remove all the build files and intermediate build outputs"
dependsOn(gradle.includedBuild("gradle-plugin").task(":clean"))
subprojects.forEach {
if (
it.project.plugins.hasPlugin("com.android.library") ||
it.project.plugins.hasPlugin("com.android.application")
) {
if (it.project.plugins.hasPlugin("com.android.library") ||
it.project.plugins.hasPlugin("com.android.application")) {
dependsOn(it.tasks.named("clean"))
}
}
@@ -82,13 +76,10 @@ tasks.register("clean", Delete::class.java) {
delete(rootProject.file("./packages/react-native/sdks/download/"))
delete(rootProject.file("./packages/react-native/sdks/hermes/"))
delete(
rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/arm64-v8a/")
)
rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/arm64-v8a/"))
delete(
rootProject.file(
"./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/armeabi-v7a/"
)
)
"./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/armeabi-v7a/"))
delete(rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/x86/"))
delete(rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/x86_64/"))
delete(rootProject.file("./packages/react-native-codegen/lib"))
@@ -106,8 +97,7 @@ tasks.register("publishAllToMavenTempLocal") {
dependsOn(":packages:react-native:ReactAndroid:publishAllPublicationsToMavenTempLocalRepository")
// We don't publish the external-artifacts to Maven Local as ci is using it via workspace.
dependsOn(
":packages:react-native:ReactAndroid:hermes-engine:publishAllPublicationsToMavenTempLocalRepository"
)
":packages:react-native:ReactAndroid:hermes-engine:publishAllPublicationsToMavenTempLocalRepository")
}
tasks.register("publishAndroidToSonatype") {
@@ -129,56 +119,14 @@ if (project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoole
That's fine for local development, but you should not commit this change.
********************************************************************************
"""
.trimIndent()
)
.trimIndent())
allprojects {
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute(project(":packages:react-native:ReactAndroid:hermes-engine"))
// TODO: T237406039 update coordinates
.using(module("com.facebook.react:hermes-android:0.+"))
.because("Users opted to use hermes from nightly")
}
}
}
}
ktfmt {
blockIndent.set(2)
continuationIndent.set(4)
maxWidth.set(100)
removeUnusedImports.set(false)
manageTrailingCommas.set(false)
}
// Configure ktfmt tasks to include gradle-plugin
listOf("ktfmtCheck", "ktfmtFormat").forEach { taskName ->
tasks.named(taskName) { dependsOn(gradle.includedBuild("gradle-plugin").task(":$taskName")) }
}
allprojects {
// Apply exclusions for specific files that should not be formatted
val excludePatterns =
listOf(
"**/build/**",
"**/hermes-engine/**",
"**/internal/featureflags/**",
"**/systeminfo/ReactNativeVersion.kt",
)
listOf(
com.ncorti.ktfmt.gradle.tasks.KtfmtCheckTask::class,
com.ncorti.ktfmt.gradle.tasks.KtfmtFormatTask::class,
)
.forEach { tasks.withType(it) { exclude(excludePatterns) } }
// Disable the problematic ktfmt script tasks due to symbolic link issues in subprojects
afterEvaluate {
listOf("ktfmtCheckScripts", "ktfmtFormatScripts").forEach {
tasks.findByName(it)?.enabled = false
}
}
}
// We intentionally disable the `ktfmtCheck` tasks as the formatting is primarly handled inside
// fbsource
allprojects { tasks.withType<com.ncorti.ktfmt.gradle.tasks.KtfmtCheckTask>() { enabled = false } }
-46
View File
@@ -1,46 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
declare module '@expo/spawn-async' {
type SpawnOptions = {
cwd?: string,
env?: Object,
argv0?: string,
stdio?: string | Array<any>,
detached?: boolean,
uid?: number,
gid?: number,
shell?: boolean | string,
windowsVerbatimArguments?: boolean,
windowsHide?: boolean,
encoding?: string,
ignoreStdio?: boolean,
};
declare class SpawnPromise<T> extends Promise<T> {
child: child_process$ChildProcess;
}
type SpawnResult = {
pid?: number,
output: string[],
stdout: string,
stderr: string,
status: number | null,
signal: string | null,
};
declare function spawnAsync(
command: string,
args?: $ReadOnlyArray<string>,
options?: SpawnOptions,
): SpawnPromise<SpawnResult>;
declare module.exports: typeof spawnAsync;
}
-61
View File
@@ -1,61 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
// Partial types for Octokit based on the usage in react-native-github
declare module '@octokit/rest' {
declare class Octokit {
constructor(options?: {auth?: string, ...}): this;
repos: $ReadOnly<{
listReleaseAssets: (
params: $ReadOnly<{
owner: string,
repo: string,
release_id: string,
}>,
) => Promise<{
data: Array<{
id: string,
name: string,
...
}>,
...
}>,
uploadReleaseAsset: (
params: $ReadOnly<{
owner: string,
repo: string,
release_id: string,
name: string,
data: Buffer,
headers: $ReadOnly<{
'content-type': string,
...
}>,
...
}>,
) => Promise<{
data: {
browser_download_url: string,
...
},
...
}>,
deleteReleaseAsset: (params: {
owner: string,
repo: string,
asset_id: string,
...
}) => Promise<mixed>,
}>;
}
declare export {Octokit};
}
-149
View File
@@ -1,149 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
declare module '@electron/packager' {
declare export type AsarOptions = $FlowFixMe;
declare export type ElectronDownloadRequestOptions = $FlowFixMe;
declare export type TargetDefinition = {
arch: TargetArch,
platform: TargetPlatform,
};
declare export type FinalizePackageTargetsHookFunction = (
targets: TargetDefinition[],
callback: HookFunctionErrorCallback,
) => void;
declare export type HookFunction = (
buildPath: string,
electronVersion: string,
platform: TargetPlatform,
arch: TargetArch,
callback: HookFunctionErrorCallback,
) => void;
declare export type IgnoreFunction = (path: string) => boolean;
declare export type HookFunctionErrorCallback = (err?: Error | null) => void;
declare export interface MacOSProtocol {
name: string;
schemes: string[];
}
declare export type NotaryToolCredentials = $FlowFixMe;
declare export type OsxSignOptions = $FlowFixMe;
declare export type OsxUniversalOptions = $FlowFixMe;
declare export type Win32MetadataOptions = $ReadOnly<{
CompanyName?: string,
FileDescription?: string,
OriginalFilename?: string,
ProductName?: string,
InternalName?: string,
'requested-execution-level'?:
| 'asInvoker'
| 'highestAvailable'
| 'requireAdministrator',
'application-manifest'?: string,
}>;
declare export type WindowsSignOptions = $FlowFixMe;
declare export type OfficialArch =
| 'ia32'
| 'x64'
| 'armv7l'
| 'arm64'
| 'mips64el'
| 'universal';
declare export type OfficialPlatform = 'linux' | 'win32' | 'darwin' | 'mas';
declare export type TargetArch = OfficialArch | string;
declare export type TargetPlatform = OfficialPlatform | string;
declare export type ArchOption = TargetArch | 'all';
declare export type PlatformOption = TargetPlatform | 'all';
declare export interface Options {
dir: string;
afterAsar?: HookFunction[];
afterComplete?: HookFunction[];
afterCopy?: HookFunction[];
afterCopyExtraResources?: HookFunction[];
afterExtract?: HookFunction[];
afterFinalizePackageTargets?: FinalizePackageTargetsHookFunction[];
afterInitialize?: HookFunction[];
afterPrune?: HookFunction[];
all?: boolean;
appBundleId?: string;
appCategoryType?: string;
appCopyright?: string;
appVersion?: string;
arch?: ArchOption | ArchOption[];
asar?: boolean | AsarOptions;
beforeAsar?: HookFunction[];
beforeCopy?: HookFunction[];
beforeCopyExtraResources?: HookFunction[];
buildVersion?: string;
darwinDarkModeSupport?: boolean;
derefSymlinks?: boolean;
download?: ElectronDownloadRequestOptions;
electronVersion?: string;
electronZipDir?: string;
executableName?: string;
extendHelperInfo?:
| string
| {
[property: string]: any,
};
extendInfo?:
| string
| {
[property: string]: any,
};
extraResource?: string | string[];
helperBundleId?: string;
icon?: string;
ignore?: RegExp | (string | RegExp)[] | IgnoreFunction;
junk?: boolean;
name?: string;
osxNotarize?: NotaryToolCredentials;
osxSign?: true | OsxSignOptions;
osxUniversal?: OsxUniversalOptions;
out?: string;
overwrite?: boolean;
platform?: TargetPlatform | 'all' | Array<TargetPlatform | 'all'>;
prebuiltAsar?: string;
protocols?: MacOSProtocol[];
prune?: boolean;
quiet?: boolean;
tmpdir?: string | false;
usageDescription?: {
[property: string]: string,
};
win32metadata?: Win32MetadataOptions;
windowsSign?: true | WindowsSignOptions;
}
declare function packager(options: Options): Promise<string[]>;
declare module.exports: typeof packager & {
packager: typeof packager,
default: typeof packager,
};
}
-41
View File
@@ -1,41 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
declare module 'electron-store' {
declare export type Schema = any;
declare export type Options = {
+name?: string,
defaults?: Object,
schema?: any,
migrations?: any,
beforeEachMigration?: any,
clearInvalidConfig?: boolean,
serialize?: any,
deserialize?: any,
accessPropertiesByDotNotation?: boolean,
watch?: boolean,
encryptionKey?: string | Buffer | $ReadOnlyArray<number>,
...
};
declare class ElectronStore {
constructor(options?: Options): this;
get(key: string): any;
get(key: string, defaultValue: any): any;
set(key: string, value: any): void;
set(object: Object): void;
has(key: string): boolean;
delete(key: string): void;
clear(): void;
}
declare module.exports: Class<ElectronStore>;
}
-421
View File
@@ -1,421 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
declare module 'jsonc-parser' {
/**
* Creates a JSON scanner on the given text.
* If ignoreTrivia is set, whitespaces or comments are ignored.
*/
declare export const createScanner: (
text: string,
ignoreTrivia?: boolean,
) => JSONScanner;
export type ScanError = number;
export type SyntaxKind = number;
/**
* The scanner object, representing a JSON scanner at a position in the input string.
*/
export type JSONScanner = $ReadOnly<{
/**
* Sets the scan position to a new offset. A call to 'scan' is needed to get the first token.
*/
setPosition(pos: number): void,
/**
* Read the next token. Returns the token code.
*/
scan(): SyntaxKind,
/**
* Returns the zero-based current scan position, which is after the last read token.
*/
getPosition(): number,
/**
* Returns the last read token.
*/
getToken(): SyntaxKind,
/**
* Returns the last read token value. The value for strings is the decoded string content. For numbers it's of type number, for boolean it's true or false.
*/
getTokenValue(): string,
/**
* The zero-based start offset of the last read token.
*/
getTokenOffset(): number,
/**
* The length of the last read token.
*/
getTokenLength(): number,
/**
* The zero-based start line number of the last read token.
*/
getTokenStartLine(): number,
/**
* The zero-based start character (column) of the last read token.
*/
getTokenStartCharacter(): number,
/**
* An error code of the last scan.
*/
getTokenError(): ScanError,
}>;
/**
* For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.
*/
declare export const getLocation: (
text: string,
position: number,
) => Location;
/**
* Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
* Therefore, always check the errors list to find out if the input was valid.
*/
declare export const parse: (
text: string,
errors?: ParseError[],
options?: ParseOptions,
) => any;
/**
* Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
*/
declare export const parseTree: (
text: string,
errors?: ParseError[],
options?: ParseOptions,
) => Node | void;
/**
* Finds the node at the given path in a JSON DOM.
*/
declare export const findNodeAtLocation: (
root: Node,
path: JSONPath,
) => Node | void;
/**
* Finds the innermost node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.
*/
declare export const findNodeAtOffset: (
root: Node,
offset: number,
includeRightBound?: boolean,
) => Node | void;
/**
* Gets the JSON path of the given JSON DOM node
*/
declare export const getNodePath: (node: Node) => JSONPath;
/**
* Evaluates the JavaScript object of the given JSON DOM node
*/
declare export const getNodeValue: (node: Node) => any;
/**
* Parses the given text and invokes the visitor functions for each object, array and literal reached.
*/
declare export const visit: (
text: string,
visitor: JSONVisitor,
options?: ParseOptions,
) => any;
/**
* Takes JSON with JavaScript-style comments and remove
* them. Optionally replaces every none-newline character
* of comments with a replaceCharacter
*/
declare export const stripComments: (
text: string,
replaceCh?: string,
) => string;
export type ParseError = {
error: ParseErrorCode,
offset: number,
length: number,
};
export type ParseErrorCode = number;
declare export function printParseErrorCode(
code: ParseErrorCode,
):
| 'InvalidSymbol'
| 'InvalidNumberFormat'
| 'PropertyNameExpected'
| 'ValueExpected'
| 'ColonExpected'
| 'CommaExpected'
| 'CloseBraceExpected'
| 'CloseBracketExpected'
| 'EndOfFileExpected'
| 'InvalidCommentToken'
| 'UnexpectedEndOfComment'
| 'UnexpectedEndOfString'
| 'UnexpectedEndOfNumber'
| 'InvalidUnicode'
| 'InvalidEscapeCharacter'
| 'InvalidCharacter'
| '<unknown ParseErrorCode>';
export type NodeType =
| 'object'
| 'array'
| 'property'
| 'string'
| 'number'
| 'boolean'
| 'null';
export type Node = {
type: NodeType,
value?: any,
offset: number,
length: number,
colonOffset?: number,
parent?: Node,
children?: Node[],
};
/**
* A {@linkcode JSONPath} segment. Either a string representing an object property name
* or a number (starting at 0) for array indices.
*/
export type Segment = string | number;
export type JSONPath = Segment[];
export type Location = {
/**
* The previous property key or literal value (string, number, boolean or null) or undefined.
*/
previousNode?: Node,
/**
* The path describing the location in the JSON document. The path consists of a sequence of strings
* representing an object property or numbers for array indices.
*/
path: JSONPath,
/**
* Matches the locations path against a pattern consisting of strings (for properties) and numbers (for array indices).
* '*' will match a single segment of any property name or index.
* '**' will match a sequence of segments of any property name or index, or no segment.
*/
matches: (patterns: JSONPath) => boolean,
/**
* If set, the location's offset is at a property key.
*/
isAtPropertyKey: boolean,
};
export type ParseOptions = {
disallowComments?: boolean,
allowTrailingComma?: boolean,
allowEmptyContent?: boolean,
};
/**
* Visitor called by {@linkcode visit} when parsing JSON.
*
* The visitor functions have the following common parameters:
* - `offset`: Global offset within the JSON document, starting at 0
* - `startLine`: Line number, starting at 0
* - `startCharacter`: Start character (column) within the current line, starting at 0
*
* Additionally some functions have a `pathSupplier` parameter which can be used to obtain the
* current `JSONPath` within the document.
*/
export type JSONVisitor = {
/**
* Invoked when an open brace is encountered and an object is started. The offset and length represent the location of the open brace.
*/
onObjectBegin?: (
offset: number,
length: number,
startLine: number,
startCharacter: number,
pathSupplier: () => JSONPath,
) => void,
/**
* Invoked when a property is encountered. The offset and length represent the location of the property name.
* The `JSONPath` created by the `pathSupplier` refers to the enclosing JSON object, it does not include the
* property name yet.
*/
onObjectProperty?: (
property: string,
offset: number,
length: number,
startLine: number,
startCharacter: number,
pathSupplier: () => JSONPath,
) => void,
/**
* Invoked when a closing brace is encountered and an object is completed. The offset and length represent the location of the closing brace.
*/
onObjectEnd?: (
offset: number,
length: number,
startLine: number,
startCharacter: number,
) => void,
/**
* Invoked when an open bracket is encountered. The offset and length represent the location of the open bracket.
*/
onArrayBegin?: (
offset: number,
length: number,
startLine: number,
startCharacter: number,
pathSupplier: () => JSONPath,
) => void,
/**
* Invoked when a closing bracket is encountered. The offset and length represent the location of the closing bracket.
*/
onArrayEnd?: (
offset: number,
length: number,
startLine: number,
startCharacter: number,
) => void,
/**
* Invoked when a literal value is encountered. The offset and length represent the location of the literal value.
*/
onLiteralValue?: (
value: any,
offset: number,
length: number,
startLine: number,
startCharacter: number,
pathSupplier: () => JSONPath,
) => void,
/**
* Invoked when a comma or colon separator is encountered. The offset and length represent the location of the separator.
*/
onSeparator?: (
character: string,
offset: number,
length: number,
startLine: number,
startCharacter: number,
) => void,
/**
* When comments are allowed, invoked when a line or block comment is encountered. The offset and length represent the location of the comment.
*/
onComment?: (
offset: number,
length: number,
startLine: number,
startCharacter: number,
) => void,
/**
* Invoked on an error.
*/
onError?: (
error: ParseErrorCode,
offset: number,
length: number,
startLine: number,
startCharacter: number,
) => void,
};
/**
* An edit result describes a textual edit operation. It is the result of a {@linkcode format} and {@linkcode modify} operation.
* It consist of one or more edits describing insertions, replacements or removals of text segments.
* * The offsets of the edits refer to the original state of the document.
* * No two edits change or remove the same range of text in the original document.
* * Multiple edits can have the same offset if they are multiple inserts, or an insert followed by a remove or replace.
* * The order in the array defines which edit is applied first.
* To apply an edit result use {@linkcode applyEdits}.
* In general multiple EditResults must not be concatenated because they might impact each other, producing incorrect or malformed JSON data.
*/
export type EditResult = Edit[];
/**
* Represents a text modification
*/
export type Edit = {
/**
* The start offset of the modification.
*/
offset: number,
/**
* The length of the modification. Must not be negative. Empty length represents an *insert*.
*/
length: number,
/**
* The new content. Empty content represents a *remove*.
*/
content: string,
};
/**
* A text range in the document
*/
export type Range = {
/**
* The start offset of the range.
*/
offset: number,
/**
* The length of the range. Must not be negative.
*/
length: number,
};
/**
* Options used by {@linkcode format} when computing the formatting edit operations
*/
export type FormattingOptions = $ReadOnly<{
/**
* If indentation is based on spaces (`insertSpaces` = true), the number of spaces that make an indent.
*/
tabSize?: number,
/**
* Is indentation based on spaces?
*/
insertSpaces?: boolean,
/**
* The default 'end of line' character. If not set, '\n' is used as default.
*/
eol?: string,
}>;
/**
* Computes the edit operations needed to format a JSON document.
*
* @param documentText The input text
* @param range The range to format or `undefined` to format the full content
* @param options The formatting options
* @returns The edit operations describing the formatting changes to the original document following the format described in {@linkcode EditResult}.
* To apply the edit operations to the input, use {@linkcode applyEdits}.
*/
declare export function format(
documentText: string,
range: Range | void,
options: FormattingOptions,
): EditResult;
/**
* Options used by {@linkcode modify} when computing the modification edit operations
*/
export type ModificationOptions = {
/**
* Formatting options.
*/
formattingOptions: FormattingOptions,
/**
* Optional function to define the insertion index given an existing list of properties.
*/
getInsertionIndex?: (properties: string[]) => number,
};
/**
* Computes the edit operations needed to modify a value in the JSON document.
*
* @param documentText The input text
* @param path The path of the value to change. The path represents either to the document root, a property or an array item.
* If the path points to an non-existing property or item, it will be created.
* @param value The new value for the specified property or item. If the value is undefined,
* the property or item will be removed.
* @param options Options
* @returns The edit operations describing the changes to the original document, following the format described in {@linkcode EditResult}.
* To apply the edit operations to the input, use {@linkcode applyEdits}.
*/
declare export function modify(
text: string,
path: JSONPath,
value: any,
options: ModificationOptions,
): EditResult;
/**
* Applies edits to an input string.
* @param text The input text
* @param edits Edit operations following the format described in {@linkcode EditResult}.
* @returns The text with the applied edits.
* @throws An error if the edit operations are not well-formed as described in {@linkcode EditResult}.
*/
declare export function applyEdits(text: string, edits: EditResult): string;
}
@@ -91,19 +91,7 @@ declare module 'tinybench' {
beforeEach?: (this: Task) => void | Promise<void>,
};
// This is defined as an interface in tinybench but we define it as an object
// to catch problems like `overriddenDuration` being misspelled.
export type FnReturnedObject = {
overriddenDuration?: number,
};
// This type is defined as returning `unknown` instead of `void` in tinybench,
// but we type it this way to avoid mistakes (we can make breaking changes
// in our definition that they can't).
export type Fn = () =>
| Promise<void | FnReturnedObject>
| void
| FnReturnedObject;
export type Fn = () => Promise<mixed> | mixed;
declare export class Bench extends EventTarget {
concurrency: null | 'task' | 'bench';
+2 -2
View File
@@ -21,7 +21,7 @@ declare type ws$PerMessageDeflateOptions = {
maxPayload?: number,
};
/* $FlowFixMe[incompatible-type] - Found with Flow v0.143.1 upgrade
/* $FlowFixMe[incompatible-extend] - Found with Flow v0.143.1 upgrade
* "on" definition failing with string is incompatible with string literal */
declare class ws$WebSocketServer extends events$EventEmitter {
/**
@@ -141,7 +141,7 @@ declare type ws$UnexpectedResponseListener = (
) => mixed;
declare type ws$UpgradeListener = (response: http$IncomingMessage<>) => mixed;
/* $FlowFixMe[incompatible-type] - Found with Flow v0.143.1 upgrade
/* $FlowFixMe[incompatible-extend] - Found with Flow v0.143.1 upgrade
* "on" definition failing with string is incompatible with string literal */
declare class ws$WebSocket extends events$EventEmitter {
static Server: typeof ws$WebSocketServer;
-3
View File
@@ -12,6 +12,3 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# Controls whether to use Hermes from nightly builds. This will speed up builds
# but should NOT be turned on for CI or release builds.
react.internal.useHermesNightly=false
# Controls whether to use Hermes 1.0. Clean and rebuild when changing.
hermesV1Enabled=false
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+1 -1
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015 the original authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
+3 -3
View File
@@ -32,7 +32,7 @@ if (process.env.FBSOURCE_ENV === '1') {
require('@fb-tools/babel-register');
} else {
// Register Babel to allow local packages to be loaded from source
require('../scripts/shared/babelRegister').registerForMonorepo();
require('../scripts/babel-register').registerForMonorepo();
}
const transformer = require('@react-native/metro-babel-transformer');
@@ -86,7 +86,7 @@ module.exports = {
globalPrefix: '',
hermesParser: true,
hot: false,
// $FlowFixMe[incompatible-type] TODO: Remove when `inlineRequires` has been removed from metro-babel-transformer in OSS
// $FlowFixMe[incompatible-call] TODO: Remove when `inlineRequires` has been removed from metro-babel-transformer in OSS
inlineRequires: true,
minify: false,
platform: '',
@@ -111,7 +111,7 @@ module.exports = {
return generate(
ast,
// $FlowFixMe[incompatible-type] Error found when improving flow typing for libs
// $FlowFixMe[prop-missing] Error found when improving flow typing for libs
{
code: true,
comments: false,
+24 -37
View File
@@ -8,19 +8,15 @@
"android": "yarn --cwd packages/rn-tester android",
"build-android": "./gradlew :packages:react-native:ReactAndroid:build",
"build": "node ./scripts/build/build.js",
"build-types": "node ./scripts/js-api/build-types",
"build-types": "node ./scripts/build-types",
"clang-format": "clang-format -i --glob=*/**/*.{h,cpp,m,mm}",
"clean": "node ./scripts/build/clean.js",
"cxx-api-build": "node ./scripts/cxx-api/public-api.js",
"flow-check": "flow check",
"flow": "flow",
"format-check": "prettier --list-different \"./**/*.{js,md,yml,ts,tsx}\"",
"format": "npm run prettier && npm run clang-format",
"featureflags": "yarn --cwd packages/react-native featureflags",
"js-api-diff": "node ./scripts/js-api/diff-api-snapshot",
"lint-ci": "./.github/workflow-scripts/analyze_code.sh && yarn shellcheck",
"lint-kotlin-check": "./gradlew ktfmtCheck",
"lint-kotlin": "./gradlew ktfmtFormat",
"lint-markdown": "markdownlint-cli2 2>&1",
"lint": "eslint --max-warnings 0 .",
"prettier": "prettier --write \"./**/*.{js,md,yml,ts,tsx}\"",
@@ -30,8 +26,8 @@
"set-version": "node ./scripts/releases/set-version.js",
"test-android": "./gradlew :packages:react-native:ReactAndroid:test",
"test-ci": "jest --maxWorkers=2 --ci --reporters=\"default\" --reporters=\"jest-junit\"",
"test-release-local-clean": "node ./scripts/release-testing/test-release-local-clean.js",
"test-release-local": "node ./scripts/release-testing/test-release-local.js",
"test-e2e-local-clean": "node ./scripts/release-testing/test-e2e-local-clean.js",
"test-e2e-local": "node ./scripts/release-testing/test-e2e-local.js",
"test-ios": "./scripts/objc-test.sh test",
"test-typescript": "tsc -p packages/react-native/types/tsconfig.json",
"test-generated-typescript": "tsc -p packages/react-native/types_generated/tsconfig.test.json",
@@ -53,20 +49,16 @@
"@babel/plugin-transform-regenerator": "^7.24.7",
"@babel/preset-env": "^7.25.3",
"@babel/preset-flow": "^7.24.7",
"@electron/packager": "^18.3.6",
"@expo/spawn-async": "^1.7.2",
"@jest/create-cache-key-function": "^29.7.0",
"@microsoft/api-extractor": "^7.52.2",
"@octokit/rest": "^22.0.0",
"@react-native/metro-babel-transformer": "0.82.0-main",
"@react-native/metro-config": "0.82.0-main",
"@react-native/metro-babel-transformer": "0.80.0-main",
"@react-native/metro-config": "0.80.0-main",
"@tsconfig/node22": "22.0.2",
"@types/react": "^19.1.0",
"@typescript-eslint/parser": "^8.36.0",
"ansi-regex": "^5.0.0",
"@typescript-eslint/parser": "^7.1.1",
"ansi-styles": "^4.2.1",
"babel-plugin-minify-dead-code-elimination": "^0.5.2",
"babel-plugin-syntax-hermes-parser": "0.32.0",
"babel-plugin-syntax-hermes-parser": "0.29.1",
"babel-plugin-transform-define": "^2.1.4",
"babel-plugin-transform-flow-enums": "^0.0.2",
"clang-format": "^1.8.0",
@@ -78,51 +70,46 @@
"eslint-plugin-babel": "^5.3.1",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-ft-flow": "^2.0.1",
"eslint-plugin-jest": "^29.0.1",
"eslint-plugin-jest": "^27.9.0",
"eslint-plugin-jsx-a11y": "^6.6.0",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-native": "^4.0.0",
"eslint-plugin-redundant-undefined": "^0.4.0",
"eslint-plugin-relay": "^1.8.3",
"fb-dotslash": "0.5.8",
"flow-api-translator": "0.32.0",
"flow-bin": "^0.281.0",
"flow-api-translator": "0.29.1",
"flow-bin": "^0.274.2",
"glob": "^7.1.1",
"hermes-eslint": "0.32.0",
"hermes-transform": "0.32.0",
"ini": "^5.0.0",
"hermes-eslint": "0.29.1",
"hermes-transform": "0.29.1",
"inquirer": "^7.1.0",
"jest": "^29.7.0",
"jest-config": "^29.7.0",
"jest-diff": "^29.7.0",
"jest-junit": "^16.0.0",
"jest-junit": "^10.0.0",
"jest-snapshot": "^29.7.0",
"jsonc-parser": "2.2.1",
"markdownlint-cli2": "^0.17.2",
"markdownlint-rule-relative-links": "^3.0.0",
"memfs": "^4.38.2",
"metro-babel-register": "^0.83.1",
"metro-transform-plugins": "^0.83.1",
"metro-babel-register": "^0.82.4",
"metro-memory-fs": "^0.82.4",
"metro-transform-plugins": "^0.82.4",
"micromatch": "^4.0.4",
"node-fetch": "^2.2.0",
"nullthrows": "^1.1.1",
"prettier": "3.6.2",
"prettier-plugin-hermes-parser": "0.32.0",
"react": "19.1.1",
"react-test-renderer": "19.1.1",
"prettier": "2.8.8",
"prettier-plugin-hermes-parser": "0.29.1",
"react": "19.1.0",
"react-test-renderer": "19.1.0",
"rimraf": "^3.0.2",
"shelljs": "^0.8.5",
"signedsource": "^2.0.0",
"signedsource": "^1.0.0",
"supports-color": "^7.1.0",
"temp-dir": "^2.0.0",
"tinybench": "^4.1.0",
"tinybench": "^3.1.0",
"typescript": "5.8.3",
"ws": "^7.5.10"
"ws": "^6.2.3"
},
"resolutions": {
"eslint-plugin-react-hooks": "6.1.0-canary-12bc60f5-20250613",
"react-is": "19.1.1",
"on-headers": "1.1.0",
"compression": "1.8.1"
"react-is": "19.1.0"
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/assets-registry",
"version": "0.82.0-main",
"version": "0.80.0-main",
"description": "Asset support code for React Native.",
"license": "MIT",
"repository": {
@@ -17,7 +17,7 @@
],
"bugs": "https://github.com/facebook/react-native/issues",
"engines": {
"node": ">= 20.19.4"
"node": ">= 22.14.0"
},
"files": [
"path-support.js",
@@ -81,147 +81,10 @@ export {Commands};
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COVERAGE_INVALID = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
// Coverage instrumentation of invalid Commands export - should still fail
export const Commands = (cov_1234567890().s[0]++, {
hotspotUpdate: () => {},
scrollTo: () => {},
});
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COVERAGE_WRONG_FUNCTION = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
// Coverage instrumentation of wrong function call - should fail
export const Commands = (cov_abcdef123().s[0]++, someOtherFunction({
supportedCommands: ['pause', 'play'],
}));
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COMPLEX_COVERAGE_INVALID = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
// Complex coverage instrumentation with invalid nested structure - should fail
export const Commands = (
cov_xyz789().f[1]++,
cov_xyz789().s[2]++,
{
pause: (ref) => {},
play: (ref) => {},
}
);
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COVERAGE_WRONG_NAME = `
// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+pause: (viewRef: React.ElementRef<NativeType>) => void;
+play: (viewRef: React.ElementRef<NativeType>) => void;
}
// Coverage instrumentation with correct function but wrong export name - should fail
export const WrongName = (cov_wrong123().s[0]++, codegenNativeCommands<NativeCommands>({
supportedCommands: ['pause', 'play'],
}));
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COVERAGE_TYPE_CAST_INVALID = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+pause: (viewRef: React.ElementRef<NativeType>) => void;
+play: (viewRef: React.ElementRef<NativeType>) => void;
}
// Coverage instrumentation with type cast but wrong function - should fail
export const Commands: NativeCommands = (cov_cast123().s[0]++, invalidFunction({
supportedCommands: ['pause', 'play'],
}));
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
module.exports = {
'CommandsExportedWithDifferentNameNativeComponent.js':
COMMANDS_EXPORTED_WITH_DIFFERENT_NAME,
'CommandsExportedWithShorthandNativeComponent.js':
COMMANDS_EXPORTED_WITH_SHORTHAND,
'OtherCommandsExportNativeComponent.js': OTHER_COMMANDS_EXPORT,
'CommandsWithCoverageInvalidNativeComponent.js':
COMMANDS_WITH_COVERAGE_INVALID,
'CommandsWithCoverageWrongFunctionNativeComponent.js':
COMMANDS_WITH_COVERAGE_WRONG_FUNCTION,
'CommandsWithComplexCoverageInvalidNativeComponent.js':
COMMANDS_WITH_COMPLEX_COVERAGE_INVALID,
'CommandsWithCoverageWrongNameNativeComponent.js':
COMMANDS_WITH_COVERAGE_WRONG_NAME,
'CommandsWithCoverageTypeCastInvalidNativeComponent.js':
COMMANDS_WITH_COVERAGE_TYPE_CAST_INVALID,
};
@@ -59,92 +59,6 @@ export default codegenNativeComponent<ModuleProps>('Module', {
});
`;
// Coverage instrumentation test cases - should be recognized as valid
const COMMANDS_WITH_SIMPLE_COVERAGE = `
// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
import type {NativeComponentType} from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+pause: (viewRef: React.ElementRef<NativeType>) => void;
+play: (viewRef: React.ElementRef<NativeType>) => void;
}
export const Commands = (cov_1234567890.s[0]++, codegenNativeCommands<NativeCommands>({
supportedCommands: ['pause', 'play'],
}));
export default codegenNativeComponent<ModuleProps>('Module');
`;
const COMMANDS_WITH_COMPLEX_COVERAGE = `
// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
import type {NativeComponentType} from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+seek: (viewRef: React.ElementRef<NativeType>, position: number) => void;
+stop: (viewRef: React.ElementRef<NativeType>) => void;
}
export const Commands = (
cov_abcdef123().f[2]++,
cov_abcdef123().s[5]++,
codegenNativeCommands<NativeCommands>({
supportedCommands: ['seek', 'stop'],
})
);
export default codegenNativeComponent<ModuleProps>('Module');
`;
const COMMANDS_WITH_TYPE_CAST_COVERAGE = `
// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
import type {NativeComponentType} from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+mute: (viewRef: React.ElementRef<NativeType>) => void;
+unmute: (viewRef: React.ElementRef<NativeType>) => void;
}
export const Commands: NativeCommands = (cov_xyz789().s[1]++, codegenNativeCommands<NativeCommands>({
supportedCommands: ['mute', 'unmute'],
}));
export default codegenNativeComponent<ModuleProps>('Module');
`;
const FULL_NATIVE_COMPONENT_WITH_TYPE_EXPORT = `
// @flow
@@ -193,9 +107,4 @@ module.exports = {
'NotANativeComponent.js': NOT_A_NATIVE_COMPONENT,
'FullNativeComponent.js': FULL_NATIVE_COMPONENT,
'FullTypedNativeComponent.js': FULL_NATIVE_COMPONENT_WITH_TYPE_EXPORT,
'CommandsWithSimpleCoverageNativeComponent.js': COMMANDS_WITH_SIMPLE_COVERAGE,
'CommandsWithComplexCoverageNativeComponent.js':
COMMANDS_WITH_COMPLEX_COVERAGE,
'CommandsWithTypeCastCoverageNativeComponent.js':
COMMANDS_WITH_TYPE_CAST_COVERAGE,
};
@@ -1,77 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Babel plugin inline view configs can inline config for CommandsWithComplexCoverageNativeComponent.js 1`] = `
"// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type { ViewProps } from 'ViewPropTypes';
import type { NativeComponentType } from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+seek: (viewRef: React.ElementRef<NativeType>, position: number) => void,
+stop: (viewRef: React.ElementRef<NativeType>) => void,
}
const NativeComponentRegistry = require('react-native/Libraries/NativeComponent/NativeComponentRegistry');
let nativeComponentName = 'Module';
export const __INTERNAL_VIEW_CONFIG = {
uiViewClassName: \\"Module\\",
validAttributes: {}
};
export default NativeComponentRegistry.get(nativeComponentName, () => __INTERNAL_VIEW_CONFIG);"
`;
exports[`Babel plugin inline view configs can inline config for CommandsWithSimpleCoverageNativeComponent.js 1`] = `
"// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type { ViewProps } from 'ViewPropTypes';
import type { NativeComponentType } from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+pause: (viewRef: React.ElementRef<NativeType>) => void,
+play: (viewRef: React.ElementRef<NativeType>) => void,
}
const NativeComponentRegistry = require('react-native/Libraries/NativeComponent/NativeComponentRegistry');
let nativeComponentName = 'Module';
export const __INTERNAL_VIEW_CONFIG = {
uiViewClassName: \\"Module\\",
validAttributes: {}
};
export default NativeComponentRegistry.get(nativeComponentName, () => __INTERNAL_VIEW_CONFIG);"
`;
exports[`Babel plugin inline view configs can inline config for CommandsWithTypeCastCoverageNativeComponent.js 1`] = `
"// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type { ViewProps } from 'ViewPropTypes';
import type { NativeComponentType } from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+mute: (viewRef: React.ElementRef<NativeType>) => void,
+unmute: (viewRef: React.ElementRef<NativeType>) => void,
}
const NativeComponentRegistry = require('react-native/Libraries/NativeComponent/NativeComponentRegistry');
let nativeComponentName = 'Module';
export const __INTERNAL_VIEW_CONFIG = {
uiViewClassName: \\"Module\\",
validAttributes: {}
};
export default NativeComponentRegistry.get(nativeComponentName, () => __INTERNAL_VIEW_CONFIG);"
`;
exports[`Babel plugin inline view configs can inline config for FullNativeComponent.js 1`] = `
"// @flow
@@ -225,61 +153,6 @@ exports[`Babel plugin inline view configs fails on inline config for CommandsExp
24 |"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithComplexCoverageInvalidNativeComponent.js 1`] = `
"/CommandsWithComplexCoverageInvalidNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
14 |
15 | // Complex coverage instrumentation with invalid nested structure - should fail
> 16 | export const Commands = (
| ^
17 | cov_xyz789().f[1]++,
18 | cov_xyz789().s[2]++,
19 | {"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithCoverageInvalidNativeComponent.js 1`] = `
"/CommandsWithCoverageInvalidNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
14 |
15 | // Coverage instrumentation of invalid Commands export - should still fail
> 16 | export const Commands = (cov_1234567890().s[0]++, {
| ^
17 | hotspotUpdate: () => {},
18 | scrollTo: () => {},
19 | });"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithCoverageTypeCastInvalidNativeComponent.js 1`] = `
"/CommandsWithCoverageTypeCastInvalidNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
19 |
20 | // Coverage instrumentation with type cast but wrong function - should fail
> 21 | export const Commands: NativeCommands = (cov_cast123().s[0]++, invalidFunction({
| ^
22 | supportedCommands: ['pause', 'play'],
23 | }));
24 |"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithCoverageWrongFunctionNativeComponent.js 1`] = `
"/CommandsWithCoverageWrongFunctionNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
14 |
15 | // Coverage instrumentation of wrong function call - should fail
> 16 | export const Commands = (cov_abcdef123().s[0]++, someOtherFunction({
| ^
17 | supportedCommands: ['pause', 'play'],
18 | }));
19 |"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithCoverageWrongNameNativeComponent.js 1`] = `
"/CommandsWithCoverageWrongNameNativeComponent.js: Native commands must be exported with the name 'Commands'
20 |
21 | // Coverage instrumentation with correct function but wrong export name - should fail
> 22 | export const WrongName = (cov_wrong123().s[0]++, codegenNativeCommands<NativeCommands>({
| ^
23 | supportedCommands: ['pause', 'play'],
24 | }));
25 |"
`;
exports[`Babel plugin inline view configs fails on inline config for OtherCommandsExportNativeComponent.js 1`] = `
"/OtherCommandsExportNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
17 | }
+9 -61
View File
@@ -24,12 +24,12 @@ try {
} catch (e) {
// Fallback to lib when source doesn't exit (e.g. when installed as a dev dependency)
FlowParser =
// $FlowFixMe[cannot-resolve-module]
// $FlowIgnore[cannot-resolve-module]
require('@react-native/codegen/lib/parsers/flow/parser').FlowParser;
TypeScriptParser =
// $FlowFixMe[cannot-resolve-module]
// $FlowIgnore[cannot-resolve-module]
require('@react-native/codegen/lib/parsers/typescript/parser').TypeScriptParser;
// $FlowFixMe[cannot-resolve-module]
// $FlowIgnore[cannot-resolve-module]
RNCodegen = require('@react-native/codegen/lib/generators/RNCodegen');
}
@@ -102,58 +102,6 @@ function isCodegenDeclaration(declaration) {
return false;
}
function isCodegenNativeCommandsDeclaration(declaration) {
if (!declaration) {
return false;
}
// Handle direct calls: codegenNativeCommands()
if (
declaration.type === 'CallExpression' &&
declaration.callee &&
declaration.callee.type === 'Identifier' &&
declaration.callee.name === 'codegenNativeCommands'
) {
return true;
}
// Handle coverage instrumentation: (cov_xxx().s[0]++, codegenNativeCommands())
if (declaration.type === 'SequenceExpression' && declaration.expressions) {
// Get the last expression in the sequence (the actual function call)
const lastExpression =
declaration.expressions[declaration.expressions.length - 1];
// Recursively check if the last expression is a valid codegenNativeCommands call
return isCodegenNativeCommandsDeclaration(lastExpression);
}
// Handle Flow type casts: (codegenNativeCommands(): NativeCommands)
if (
(declaration.type === 'TypeCastExpression' ||
declaration.type === 'AsExpression') &&
declaration.expression &&
declaration.expression.type === 'CallExpression' &&
declaration.expression.callee &&
declaration.expression.callee.type === 'Identifier' &&
declaration.expression.callee.name === 'codegenNativeCommands'
) {
return true;
}
// Handle TypeScript assertions: codegenNativeCommands() as NativeCommands
if (
declaration.type === 'TSAsExpression' &&
declaration.expression &&
declaration.expression.type === 'CallExpression' &&
declaration.expression.callee &&
declaration.expression.callee.type === 'Identifier' &&
declaration.expression.callee.name === 'codegenNativeCommands'
) {
return true;
}
return false;
}
module.exports = function ({parse, types: t}) {
return {
pre(state) {
@@ -177,12 +125,12 @@ module.exports = function ({parse, types: t}) {
const firstDeclaration = path.node.declaration.declarations[0];
if (firstDeclaration.type === 'VariableDeclarator') {
// Check if this is a valid codegenNativeCommands call, handling type annotations
const isValidCommandsExport = isCodegenNativeCommandsDeclaration(
firstDeclaration.init,
);
if (isValidCommandsExport) {
if (
firstDeclaration.init &&
firstDeclaration.init.type === 'CallExpression' &&
firstDeclaration.init.callee.type === 'Identifier' &&
firstDeclaration.init.callee.name === 'codegenNativeCommands'
) {
if (
firstDeclaration.id.type === 'Identifier' &&
firstDeclaration.id.name !== 'Commands'
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/babel-plugin-codegen",
"version": "0.82.0-main",
"version": "0.80.0-main",
"description": "Babel plugin to generate native module and view manager code for React Native.",
"license": "MIT",
"repository": {
@@ -19,14 +19,14 @@
],
"bugs": "https://github.com/facebook/react-native/issues",
"engines": {
"node": ">= 20.19.4"
"node": ">= 22.14.0"
},
"files": [
"index.js"
],
"dependencies": {
"@babel/traverse": "^7.25.3",
"@react-native/codegen": "0.82.0-main"
"@react-native/codegen": "0.80.0-main"
},
"devDependencies": {
"@babel/core": "^7.25.2"
+7 -10
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/community-cli-plugin",
"version": "0.82.0-main",
"version": "0.80.0-main",
"description": "Core CLI commands for React Native",
"keywords": [
"react-native",
@@ -22,16 +22,16 @@
"dist"
],
"dependencies": {
"@react-native/dev-middleware": "0.82.0-main",
"@react-native/dev-middleware": "0.80.0-main",
"debug": "^4.4.0",
"invariant": "^2.2.4",
"metro": "^0.83.1",
"metro-config": "^0.83.1",
"metro-core": "^0.83.1",
"metro": "^0.82.4",
"metro-config": "^0.82.4",
"metro-core": "^0.82.4",
"semver": "^7.1.3"
},
"devDependencies": {
"metro-resolver": "^0.83.1"
"metro-resolver": "^0.82.4"
},
"peerDependencies": {
"@react-native-community/cli": "*",
@@ -40,12 +40,9 @@
"peerDependenciesMeta": {
"@react-native-community/cli": {
"optional": true
},
"@react-native/metro-config": {
"optional": true
}
},
"engines": {
"node": ">= 20.19.4"
"node": ">= 22.14.0"
}
}
@@ -116,7 +116,7 @@ function copyAll(filesToCopy: CopiedFiles) {
const src = queue.shift();
// $FlowFixMe[incompatible-type]
const dest = filesToCopy[src];
// $FlowFixMe[incompatible-type]
// $FlowFixMe[incompatible-call]
copy(src, dest, copyNext);
}
};
@@ -31,9 +31,9 @@ type MiddlewareReturn = {
...
};
// $FlowFixMe[incompatible-type]
// $FlowFixMe
const unusedStubWSServer: ws$WebSocketServer = {};
// $FlowFixMe[incompatible-type]
// $FlowFixMe
const unusedMiddlewareStub: Server = {};
const communityMiddlewareFallback = {
@@ -80,7 +80,7 @@ try {
'@react-native-community/cli-server-api',
{paths: [communityCliPath]},
);
// $FlowFixMe[unsupported-syntax] dynamic import
// $FlowIgnore[unsupported-syntax] dynamic import
communityMiddlewareFallback.createDevServerMiddleware = require(
communityCliServerApiPath,
).createDevServerMiddleware as CreateDevServerMiddleware;
@@ -92,14 +92,14 @@ async function runServer(
console.info(`Starting dev server on ${devServerUrl}\n`);
if (args.assetPlugins) {
// $FlowFixMe[cannot-write] Assigning to readonly property
// $FlowIgnore[cannot-write] Assigning to readonly property
metroConfig.transformer.assetPlugins = args.assetPlugins.map(plugin =>
require.resolve(plugin),
);
}
// TODO(T214991636): Remove legacy Metro log forwarding
if (!args.clientLogs) {
// $FlowFixMe[cannot-write] Assigning to readonly property
// $FlowIgnore[cannot-write] Assigning to readonly property
metroConfig.server.forwardClientLogs = false;
}
@@ -127,8 +127,6 @@ async function runServer(
const reporter: Reporter = {
update(event: TerminalReportableEvent) {
terminalReporter.update(event);
/* $FlowFixMe[constant-condition] Error discovered during Constant
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
if (reportEvent) {
reportEvent(event);
}
@@ -146,10 +144,10 @@ async function runServer(
}
},
};
// $FlowFixMe[cannot-write] Assigning to readonly property
// $FlowIgnore[cannot-write] Assigning to readonly property
metroConfig.reporter = reporter;
await Metro.runServer(metroConfig, {
const serverInstance = await Metro.runServer(metroConfig, {
host: args.host,
secure: args.https,
secureCert: args.cert,
@@ -163,6 +161,18 @@ async function runServer(
reportEvent = eventsSocketEndpoint.reportEvent;
// In Node 8, the default keep-alive for an HTTP connection is 5 seconds. In
// early versions of Node 8, this was implemented in a buggy way which caused
// some HTTP responses (like those containing large JS bundles) to be
// terminated early.
//
// As a workaround, arbitrarily increase the keep-alive from 5 to 30 seconds,
// which should be enough to send even the largest of JS bundles.
//
// For more info: https://github.com/nodejs/node/issues/13391
//
serverInstance.keepAliveTimeout = 30000;
await version.logIfUpdateAvailable(cliConfig, terminalReporter);
}
@@ -175,7 +185,7 @@ function getReporterImpl(
try {
// First we let require resolve it, so we can require packages in node_modules
// as expected. eg: require('my-package/reporter');
// $FlowFixMe[unsupported-syntax]
// $FlowIgnore[unsupported-syntax]
return require(customLogReporterPath);
} catch (e) {
if (e.code !== 'MODULE_NOT_FOUND') {
@@ -183,7 +193,7 @@ function getReporterImpl(
}
// If that doesn't work, then we next try relative to the cwd, eg:
// require('./reporter');
// $FlowFixMe[unsupported-syntax]
// $FlowIgnore[unsupported-syntax]
return require(path.resolve(customLogReporterPath));
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ export type * from './index.flow';
*/
if (!process.env.BUILD_EXCLUDE_BABEL_REGISTER) {
require('../../../scripts/shared/babelRegister').registerForMonorepo();
require('../../../scripts/babel-register').registerForMonorepo();
}
module.exports = require('./index.flow');
@@ -88,6 +88,7 @@ Diff: ${styleText(['dim', 'underline'], newVersion?.diffUrl ?? 'none')}
}
}
// $FlowFixMe
function isDiffPurgeEntry(data: Partial<DiffPurge>): data is DiffPurge {
return (
// $FlowFixMe[incompatible-type-guard]
@@ -152,7 +153,7 @@ function buildDiffUrl(oldVersion: string, newVersion: string) {
* Returns the most recent React Native version available to upgrade to.
*/
async function getLatestRnDiffPurgeVersion(): Promise<LatestVersions | void> {
const options: RequestOptions = {
const options = {
// https://developer.github.com/v3/#user-agent-required
headers: {'User-Agent': '@react-native/community-cli-plugin'} as Headers,
};
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/core-cli-utils",
"version": "0.82.0-main",
"version": "0.80.0-main",
"description": "React Native CLI library for Frameworks to build on",
"license": "MIT",
"main": "./src/index.flow.js",
@@ -21,7 +21,7 @@
],
"bugs": "https://github.com/facebook/react-native/issues",
"engines": {
"node": ">= 20.19.4"
"node": ">= 22.14.0"
},
"files": [
"dist"
+1 -1
View File
@@ -13,7 +13,7 @@ export type * from './index.flow';
*/
if (process.env.BUILD_EXCLUDE_BABEL_REGISTER == null) {
require('../../../scripts/shared/babelRegister').registerForMonorepo();
require('../../../scripts/babel-register').registerForMonorepo();
}
module.exports = require('./index.flow');
+4 -3
View File
@@ -71,13 +71,14 @@ const FIRST = 1,
FOURTH = 4;
function getNodePackagePath(packageName: string): string {
// $FlowFixMe[prop-missing] type definition is incomplete
// $FlowIgnore[prop-missing] type definition is incomplete
return require.resolve(packageName, {cwd: [process.cwd(), ...module.paths]});
}
function metro(...args: $ReadOnlyArray<string>): ExecaPromise {
log(`🚇 metro ${args.join(' ')} `);
return execa('npx', ['--offline', 'metro', ...args]);
const metroPath = getNodePackagePath(path.join('metro', 'src', 'cli.js'));
log(`🚇 ${metroPath} ${args.join(' ')} `);
return execa('node', [metroPath, ...args]);
}
export const tasks = {
+1 -1
View File
@@ -75,7 +75,7 @@ const FIRST = 1,
FIFTH = 5;
function getNodePackagePath(packageName: string): string {
// $FlowFixMe[prop-missing] type definition is incomplete
// $FlowIgnore[prop-missing] type definition is incomplete
return require.resolve(packageName, {cwd: [process.cwd(), ...module.paths]});
}
@@ -13,7 +13,7 @@ export type * from './version.flow';
*/
if (process.env.BUILD_EXCLUDE_BABEL_REGISTER == null) {
require('../../../../scripts/shared/babelRegister').registerForMonorepo();
require('../../../../scripts/babel-register').registerForMonorepo();
}
module.exports = require('./version.flow');
+2 -2
View File
@@ -1,5 +1,5 @@
@generated SignedSource<<0b54f75686e4893a5444839bf621a317>>
Git revision: 5a792db1225adda206313e9bf751198a1ca7851a
@generated SignedSource<<634e06e29a06ec6a22c087e7f8b01796>>
Git revision: 35c4630bd58bbcbc6f4c54c084b4e52994dc4940
Built with --nohooks: false
Is local checkout: false
Remote URL: https://github.com/facebook/react-native-devtools-frontend
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -238,7 +238,7 @@ import"../../ui/components/icon_button/icon_button.js";import"../../ui/component
<td>${e.method}</td>
<td>${e.params?d`<code>${JSON.stringify(e.params)}</code>`:""}</td>
<td>
${e.result?d`<code>${JSON.stringify(e.result)}</code>`:e.error?d`<code>${JSON.stringify(e.error)}</code>`:"id"in e?"(pending)":""}
${e.result?d`<code>${JSON.stringify(e.result)}</code>`:e.error?d`<code>${JSON.stringify(e.error)}</code>`:"(pending)"}
</td>
<td data-value=${e.elapsedTime||0}>
${"id"in e?e.elapsedTime?U(A.sMs,{PH1:String(e.elapsedTime)}):"(pending)":""}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/debugger-frontend",
"version": "0.82.0-main",
"version": "0.80.0-main",
"description": "Debugger frontend for React Native based on Chrome DevTools",
"keywords": [
"react-native",
@@ -20,6 +20,6 @@
"BUILD_INFO"
],
"engines": {
"node": ">= 20.19.4"
"node": ">= 22.14.0"
}
}
@@ -1,33 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`prepareDebuggerShellFromDotSlashFile fails with the expected error message for a missing dotslash file 1`] = `
Object {
"code": "unexpected_error",
"humanReadableMessage": "An unexpected error occured while installing the latest version of React Native DevTools. Using a fallback version instead.",
"verboseInfo": Any<String>,
}
`;
exports[`prepareDebuggerShellFromDotSlashFile fails with the expected error message for missing platforms 1`] = `
Object {
"code": "platform_not_supported",
"humanReadableMessage": "The latest version of React Native DevTools is not supported on this platform. Using a fallback version instead.",
"verboseInfo": Any<String>,
}
`;
exports[`prepareDebuggerShellFromDotSlashFile scenarios requiring a local HTTP server fails with the expected error message for a corrupted tarball 1`] = `
Object {
"code": "possible_corruption",
"humanReadableMessage": "Failed to verify the latest version of React Native DevTools. Using a fallback version instead. ",
"verboseInfo": Any<String>,
}
`;
exports[`prepareDebuggerShellFromDotSlashFile scenarios requiring a local HTTP server fails with the expected error message for a network error 1`] = `
Object {
"code": "likely_offline",
"humanReadableMessage": "Failed to download the latest version of React Native DevTools. Using a fallback version instead. Connect to the internet or check your network settings.",
"verboseInfo": Any<String>,
}
`;

Some files were not shown because too many files have changed in this diff Show More